View Javadoc

1   /*
2    * #%L
3    * prolobjectlink-jpi
4    * %%
5    * Copyright (C) 2019 Prolobjectlink Project
6    * %%
7    * Permission is hereby granted, free of charge, to any person obtaining a copy
8    * of this software and associated documentation files (the "Software"), to deal
9    * in the Software without restriction, including without limitation the rights
10   * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11   * copies of the Software, and to permit persons to whom the Software is
12   * furnished to do so, subject to the following conditions:
13   * 
14   * The above copyright notice and this permission notice shall be included in
15   * all copies or substantial portions of the Software.
16   * 
17   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23   * THE SOFTWARE.
24   * #L%
25   */
26  package io.github.prolobjectlink.prolog;
27  
28  import java.io.File;
29  import java.util.HashSet;
30  import java.util.Map;
31  import java.util.Set;
32  
33  /**
34   * Partial implementation of {@link PrologProvider}
35   * 
36   * @author Jose Zalacain
37   * @since 1.0
38   */
39  public abstract class AbstractProvider implements PrologProvider {
40  
41  	protected final PrologConverter<?> converter;
42  	private static final Set<PrologIndicator> ISO_IEC_BUILT_INS;
43  
44  	static {
45  
46  		ISO_IEC_BUILT_INS = new HashSet<PrologIndicator>();
47  
48  		// 7.4 directives
49  		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator("dynamic", 1));
50  		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator("include", 1));
51  		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator("multifile", 1));
52  		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator("set_prolog_flag", 2));
53  		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator("ensure_loaded", 1));
54  		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator("discontiguous", 1));
55  		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator("current_prolog_flag", 2));
56  		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator("initialization", 1));
57  
58  		// 7.8 control constructs
59  		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator("nil", 0));
60  		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator("fail", 0));
61  		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator("true", 0));
62  		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator("false", 0));
63  		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator(PrologBuiltin.THROW, 1));
64  		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator(PrologBuiltin.CATCH, 3));
65  
66  		// 8.2 term unification
67  		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator("=", 2));
68  		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator("\\=", 2));
69  		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator("subsume", 2));
70  		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator(PrologBuiltin.UNIFY_WITH_OCCURS_CHECK, 2));
71  
72  		// 8.3 type testing
73  		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator(PrologBuiltin.VAR, 1));
74  		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator(PrologBuiltin.ATOM, 1));
75  		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator(PrologBuiltin.FLOAT, 1));
76  		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator(PrologBuiltin.NUMBER, 1));
77  		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator(PrologBuiltin.NONVAR, 1));
78  		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator(PrologBuiltin.OBJECT, 1));
79  		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator(PrologBuiltin.GROUND, 1));
80  		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator(PrologBuiltin.ATOMIC, 1));
81  		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator(PrologBuiltin.INTEGER, 1));
82  		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator(PrologBuiltin.COMPOUND, 1));
83  		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator(PrologBuiltin.CALLABLE, 1));
84  		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator(PrologBuiltin.CYCLIC_TERM, 1));
85  		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator(PrologBuiltin.ACYCLIC_TERM, 1));
86  
87  		// 8.4 term comparison
88  		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator("@>", 2));
89  		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator("@<", 2));
90  		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator("==", 2));
91  		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator("@>=", 2));
92  		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator("@=<", 2));
93  		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator("\\==", 2));
94  		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator(PrologBuiltin.SORT, 2));
95  		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator(PrologBuiltin.COMPARE, 3));
96  		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator(PrologBuiltin.KEYSORT, 2));
97  
98  		// 8.5 term creation and decomposition
99  		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator(PrologBuiltin.ARG, 3));
100 		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator(PrologBuiltin.FUNCTOR, 3));
101 		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator(PrologBuiltin.COPY_TERM, 2));
102 		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator(PrologBuiltin.TERM_VARIABLES, 2));
103 
104 		// 8.6 arithmetics evaluation (operator)
105 		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator("is", 2));
106 
107 		// 8.7 arithmetic comparison (operator)
108 		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator(">", 2));
109 		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator("<", 2));
110 		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator("=<", 2));
111 		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator(">=", 2));
112 		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator("=:=", 2));
113 		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator("=\\=", 2));
114 
115 		// 8.8 clause retrieval and information ( missing predicate_property/2)
116 		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator("clause", 2));
117 		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator("current_predicate", 2));
118 
119 		// 8.9 clause creation and destruction
120 		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator("abolish", 1));
121 		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator("asserta", 1));
122 		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator("assertz", 1));
123 		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator("retract", 1));
124 
125 		// 8.10 All solutions
126 		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator("forall", 2));
127 		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator(PrologBuiltin.BAGOF, 3));
128 		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator(PrologBuiltin.SETOF, 3));
129 		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator(PrologBuiltin.FINDALL, 3));
130 
131 		// 8.11 Stream Selection and Control
132 		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator(PrologBuiltin.OPEN, 3));
133 		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator(PrologBuiltin.CLOSE, 1));
134 		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator(PrologBuiltin.OPEN, 4));
135 		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator(PrologBuiltin.CLOSE, 2));
136 		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator(PrologBuiltin.SET_INPUT, 1));
137 		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator(PrologBuiltin.SET_OUTPUT, 1));
138 		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator(PrologBuiltin.CURRENT_INPUT, 1));
139 		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator(PrologBuiltin.CURRENT_OUTPUT, 1));
140 
141 		// 8.12 character input/output
142 		// 8.13 byte input/output
143 
144 		// 8.14 Term input/output
145 		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator(PrologBuiltin.NL, 0));
146 		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator(PrologBuiltin.READ, 1));
147 		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator(PrologBuiltin.WRITE, 1));
148 
149 		// 8.15 logic and control
150 		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator("call", 1));
151 		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator("once", 1));
152 		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator("repeat", 0));
153 
154 		// 8.16 atomic term processing
155 		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator(PrologBuiltin.SUB_ATOM, 5));
156 		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator(PrologBuiltin.CHAR_CODE, 2));
157 		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator(PrologBuiltin.ATOM_CHARS, 2));
158 		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator(PrologBuiltin.ATOM_CODES, 2));
159 		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator(PrologBuiltin.ATOM_LENGTH, 2));
160 		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator(PrologBuiltin.ATOM_CONCAT, 3));
161 		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator(PrologBuiltin.NUMBER_CHARS, 2));
162 		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator(PrologBuiltin.NUMBER_CODES, 2));
163 
164 		// 8.17 Implementation defined hooks
165 		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator(PrologBuiltin.OP, 3));
166 		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator(PrologBuiltin.HALT, 0));
167 		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator(PrologBuiltin.HALT, 1));
168 		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator(PrologBuiltin.CURRENT_OP, 3));
169 		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator(PrologBuiltin.CHAR_CONVERSION, 2));
170 		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator(PrologBuiltin.CURRENT_CHAR_CONVERSION, 2));
171 
172 		// 9.1 simple arithmetic functors
173 		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator(PrologBuiltin.ABS, 1));
174 		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator(PrologBuiltin.EXP, 1));
175 		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator(PrologBuiltin.LOG, 1));
176 		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator(PrologBuiltin.SQRT, 1));
177 		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator(PrologBuiltin.CBRT, 1));
178 		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator(PrologBuiltin.FLOOR, 1));
179 		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator(PrologBuiltin.ROUND, 1));
180 		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator(PrologBuiltin.CEILING, 1));
181 		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator(PrologBuiltin.TRUNCATE, 1));
182 		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator(PrologBuiltin.FLOAT_INTEGER_PART, 1));
183 		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator(PrologBuiltin.FLOAT_FRACTIONAL_PART, 1));
184 
185 		// 9.2 ???
186 
187 		// 9.3 other arithmetic functors
188 		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator(PrologBuiltin.MAX, 2));
189 		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator(PrologBuiltin.MIN, 2));
190 		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator(PrologBuiltin.GCD, 2));
191 		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator(PrologBuiltin.LCM, 2));
192 
193 		// 9.4 bitwise functors
194 		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator("\\//", 2));
195 		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator("><", 2));
196 		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator("/\\", 2));
197 		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator("<<", 2));
198 		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator(">>", 2));
199 		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator("\\/", 1));
200 		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator("//", 2));
201 
202 		// 9.5 trigonometric functors
203 		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator(PrologBuiltin.SIN, 1));
204 		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator(PrologBuiltin.COS, 1));
205 		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator(PrologBuiltin.TAN, 1));
206 		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator(PrologBuiltin.ASIN, 1));
207 		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator(PrologBuiltin.ACOS, 1));
208 		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator(PrologBuiltin.ATAN, 1));
209 		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator(PrologBuiltin.SIGN, 1));
210 
211 		// 9.6 mathematical constants
212 		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator(PrologBuiltin.E, 0));
213 		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator(PrologBuiltin.PI, 0));
214 		ISO_IEC_BUILT_INS.add(new DefaultPrologIndicator(PrologBuiltin.EPSILON, 0));
215 
216 	}
217 
218 	public AbstractProvider(PrologConverter<?> converter) {
219 		this.converter = converter;
220 	}
221 
222 	protected final String removeQuoted(String functor) {
223 		if (functor != null && functor.startsWith("\'") && functor.endsWith("\'")) {
224 			return functor.substring(1, functor.length() - 1);
225 		}
226 		return functor;
227 	}
228 
229 	public final boolean isCompliant() {
230 		PrologEngine engine = newEngine();
231 		Set<PrologIndicator> implemented = engine.getBuiltIns();
232 		for (PrologIndicator prologIndicator : ISO_IEC_BUILT_INS) {
233 			if (implemented.contains(prologIndicator)) {
234 				return true;
235 			}
236 		}
237 		return false;
238 	}
239 
240 	public final PrologList parseList(String stringList) {
241 		PrologTerm term = parseTerm(stringList);
242 		checkListType(term);
243 		return (PrologList) term;
244 	}
245 
246 	public final PrologClause parseClause(String stringClause) {
247 		PrologEngine engine = newEngine();
248 		engine.asserta(stringClause);
249 		return engine.iterator().next();
250 	}
251 
252 	public final PrologStructure parseStructure(String stringStructure) {
253 		PrologTerm term = parseTerm(stringStructure);
254 		checkStructureType(term);
255 		return (PrologStructure) term;
256 	}
257 
258 	public final Set<PrologClause> parseProgram(String file) {
259 		return newEngine(file).getProgramClauses();
260 	}
261 
262 	public final Set<PrologClause> parseProgram(File in) {
263 		return parseProgram(in.getAbsolutePath());
264 	}
265 
266 	public final PrologFloat newFloat() {
267 		return newFloat(0F);
268 	}
269 
270 	public final PrologDouble newDouble() {
271 		return newDouble(0D);
272 	}
273 
274 	public final PrologInteger newInteger() {
275 		return newInteger(0);
276 	}
277 
278 	public final PrologLong newLong() {
279 		return newLong(0L);
280 	}
281 
282 	public final PrologList newList(PrologTerm head) {
283 		return newList(new PrologTerm[] { head });
284 	}
285 
286 	public final PrologList newList(Object head) {
287 		return newList(getJavaConverter().toTerm(head));
288 	}
289 
290 	public final PrologList newList(Object[] arguments) {
291 		return newList(getJavaConverter().toTermsArray(arguments));
292 	}
293 
294 	public final PrologList newList(Object head, Object tail) {
295 		PrologJavaConverter transformer = getJavaConverter();
296 		PrologTerm headTerm = transformer.toTerm(head);
297 		PrologTerm tailTerm = transformer.toTerm(tail);
298 		return newList(headTerm, tailTerm);
299 	}
300 
301 	public final PrologList newList(Object[] arguments, Object tail) {
302 		PrologJavaConverter transformer = getJavaConverter();
303 		PrologTerm[] array = transformer.toTermsArray(arguments);
304 		PrologTerm tailTerm = transformer.toTerm(tail);
305 		return newList(array, tailTerm);
306 	}
307 
308 	public final PrologTerm newStructure(String functor, Object... arguments) {
309 		PrologJavaConverter transformer = getJavaConverter();
310 		PrologTerm[] parameters = transformer.toTermsArray(arguments);
311 		return newStructure(functor, parameters);
312 	}
313 
314 	public final PrologTerm newStructure(Object left, String operator, Object right) {
315 		PrologJavaConverter transformer = getJavaConverter();
316 		PrologTerm leftTerm = transformer.toTerm(left);
317 		PrologTerm rightTerm = transformer.toTerm(right);
318 		return newStructure(leftTerm, operator, rightTerm);
319 	}
320 
321 	/**
322 	 * Casts a PrologTerm to the class or interface represented by this
323 	 * {@code Class} object.
324 	 *
325 	 * @param term the object to be cast
326 	 * @param type the class or interface to be casted
327 	 * @return the PrologTerm after casting, or null if term is null
328 	 *
329 	 * @throws ClassCastException if the object is not null and is not assignable to
330 	 *                            the type T.
331 	 * @since 1.1
332 	 */
333 	protected final <T extends PrologTerm> T cast(PrologTerm term, Class<T> type) {
334 		return type.cast(term);
335 	}
336 
337 	public final <T extends PrologTerm> T cast(PrologTerm term) {
338 		return (T) term;
339 	}
340 
341 	public final <K extends PrologTerm> K toTerm(Object o, Class<K> from) {
342 		return converter.toTerm(o, from);
343 	}
344 
345 	public final <K extends PrologTerm> K[] toTermArray(Object[] os, Class<K[]> from) {
346 		return converter.toTermArray(os, from);
347 	}
348 
349 	public final <K extends PrologTerm> K[][] toTermMatrix(Object[][] oss, Class<K[][]> from) {
350 		return converter.toTermMatrix(oss, from);
351 	}
352 
353 	public final <K extends PrologTerm, V extends Object> Map<String, PrologTerm> toTermMap(Map<String, V> map,
354 			Class<K> from) {
355 		return converter.toTermMap(map, from);
356 	}
357 
358 	public final <K extends PrologTerm, V extends Object> Map<String, PrologTerm>[] toTermMapArray(Map<String, V>[] map,
359 			Class<K> from) {
360 		return converter.toTermMapArray(map, from);
361 	}
362 
363 	public final PrologConverter<?> getConverter() {
364 		return converter;
365 	}
366 
367 	public final <K> K fromTerm(PrologTerm term, Class<K> to) {
368 		return converter.fromTerm(term, to);
369 	}
370 
371 	public final <K> K[] fromTermArray(PrologTerm[] terms, Class<K[]> to) {
372 		return converter.fromTermArray(terms, to);
373 	}
374 
375 	public final <K> K fromTerm(PrologTerm head, PrologTerm[] body, Class<K> to) {
376 		return converter.fromTerm(head, body, to);
377 	}
378 
379 	public final PrologParser getParser() {
380 		return this;
381 	}
382 
383 	public final String getVersion() {
384 		return newEngine().getVersion();
385 	}
386 
387 	public final String getName() {
388 		return newEngine().getName();
389 	}
390 
391 	public int hashCode() {
392 		final int prime = 31;
393 		int result = 1;
394 		result = prime * result + ((converter == null) ? 0 : converter.hashCode());
395 		return result;
396 	}
397 
398 	public boolean equals(Object object) {
399 		if (this == object)
400 			return true;
401 		if (object == null)
402 			return false;
403 		if (getClass() != object.getClass())
404 			return false;
405 		AbstractProvider other = (AbstractProvider) object;
406 		if (converter == null) {
407 			if (other.converter != null)
408 				return false;
409 		} else if (!converter.equals(other.converter)) {
410 			return false;
411 		}
412 		return true;
413 	}
414 
415 	public abstract String toString();
416 
417 	private final void checkListType(PrologTerm term) {
418 		if (!term.isList()) {
419 			throw new ListExpectedError(term);
420 		}
421 	}
422 
423 	private final void checkStructureType(PrologTerm term) {
424 		if (!term.isStructure()) {
425 			throw new StructureExpectedError(term);
426 		}
427 	}
428 
429 }