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.PrologLogger.DONT_WORRY;
25  import static io.github.prolobjectlink.prolog.PrologLogger.FILE_NOT_FOUND;
26  import static io.github.prolobjectlink.prolog.PrologLogger.INDICATOR_NOT_FOUND;
27  import static io.github.prolobjectlink.prolog.PrologLogger.IO;
28  import static io.github.prolobjectlink.prolog.PrologLogger.RUNTIME_ERROR;
29  import static io.github.prolobjectlink.prolog.PrologLogger.SYNTAX_ERROR;
30  
31  import java.io.BufferedReader;
32  import java.io.FileInputStream;
33  import java.io.FileNotFoundException;
34  import java.io.IOException;
35  import java.io.InputStream;
36  import java.io.PrintWriter;
37  import java.io.Reader;
38  import java.lang.reflect.Method;
39  import java.util.Arrays;
40  import java.util.Collection;
41  import java.util.HashSet;
42  import java.util.Iterator;
43  import java.util.LinkedList;
44  import java.util.List;
45  import java.util.Set;
46  
47  import io.github.prolobjectlink.prolog.AbstractEngine;
48  import io.github.prolobjectlink.prolog.Licenses;
49  import io.github.prolobjectlink.prolog.PrologClause;
50  import io.github.prolobjectlink.prolog.PrologEngine;
51  import io.github.prolobjectlink.prolog.PrologIndicator;
52  import io.github.prolobjectlink.prolog.PrologLogger;
53  import io.github.prolobjectlink.prolog.PrologOperator;
54  import io.github.prolobjectlink.prolog.PrologProgram;
55  import io.github.prolobjectlink.prolog.PrologProvider;
56  import io.github.prolobjectlink.prolog.PrologQuery;
57  import io.github.prolobjectlink.prolog.PrologTerm;
58  import jTrolog.engine.Prolog;
59  import jTrolog.errors.PrologException;
60  import jTrolog.lib.BuiltIn;
61  import jTrolog.lib.IOLibrary;
62  import jTrolog.lib.Library;
63  import jTrolog.parser.Parser;
64  import jTrolog.terms.Clause;
65  import jTrolog.terms.Struct;
66  import jTrolog.terms.StructAtom;
67  import jTrolog.terms.Term;
68  
69  /**
70   * 
71   * @author Jose Zalacain
72   * @since 1.0
73   */
74  public class JTrologEngine extends AbstractEngine implements PrologEngine {
75  
76  	final Prolog engine;
77  
78  	protected JTrologEngine(PrologProvider provider, Prolog engine) {
79  		super(provider);
80  		this.engine = engine;
81  	}
82  
83  	public void consult(String path) {
84  		engine.clearTheory();
85  		include(path);
86  	}
87  
88  	public void consult(Reader reader) {
89  		engine.clearTheory();
90  		include(reader);
91  	}
92  
93  	public void include(String path) {
94  		try {
95  			InputStream is = new FileInputStream(path);
96  			engine.addTheory(IOLibrary.readStream(is));
97  		} catch (FileNotFoundException e) {
98  			getLogger().warn(getClass(), FILE_NOT_FOUND + path, e);
99  		} catch (PrologException e) {
100 			getLogger().error(getClass(), SYNTAX_ERROR + path, e);
101 		} catch (IOException e) {
102 			getLogger().warn(getClass(), IO + path, e);
103 		}
104 	}
105 
106 	public void include(Reader reader) {
107 		BufferedReader bfr = new BufferedReader(reader);
108 		StringBuilder script = new StringBuilder();
109 		try {
110 			String line = bfr.readLine();
111 			while (line != null) {
112 				script.append(line);
113 				script.append("\n");
114 				line = bfr.readLine();
115 			}
116 			engine.addTheory("" + script + "");
117 		} catch (PrologException e) {
118 			getLogger().error(getClass(), SYNTAX_ERROR + script, e);
119 		} catch (IOException e) {
120 			getLogger().warn(getClass(), IO + script, e);
121 		}
122 	}
123 
124 	public void persist(String path) {
125 		PrintWriter writer = null;
126 		try {
127 			writer = new PrintWriter(path);
128 			writer.write(engine.getTheory());
129 		} catch (IOException e) {
130 			getLogger().warn(getClass(), IO + path, e);
131 			getLogger().info(getClass(), DONT_WORRY + path);
132 		} finally {
133 			if (writer != null) {
134 				writer.close();
135 			}
136 		}
137 	}
138 
139 	public void abolish(String functor, int arity) {
140 		String pi = functor + "/" + arity;
141 		try {
142 			engine.abolish(pi);
143 		} catch (PrologException e) {
144 			getLogger().error(getClass(), INDICATOR_NOT_FOUND, e);
145 		}
146 	}
147 
148 	private boolean exist(Clause clause) {
149 		String name = clause.head.name;
150 		StructAtom functor = new StructAtom(name);
151 		String key = functor + "/" + clause.head.arity;
152 		Iterator<?> i = engine.dynamicPredicateIndicators();
153 		while (i.hasNext()) {
154 			String predIndicator = (String) i.next();
155 			if (predIndicator.equals(key)) {
156 				try {
157 					List<?> list = engine.find(predIndicator);
158 					for (Object object : list) {
159 						if (object instanceof Clause) {
160 							Clause iclause = (Clause) object;
161 							if (iclause.head.equals(clause.head)) {
162 
163 								Struct[] xclausetail = iclause.tail.length > 0 ? iclause.tail
164 										: new Struct[] { (Struct) Term.TRUE };
165 								Struct[] yclausetail = clause.tail.length > 0 ? clause.tail
166 										: new Struct[] { (Struct) Term.TRUE };
167 
168 								if (xclausetail.length != yclausetail.length) {
169 									return false;
170 								}
171 
172 								for (int j = 0; j < yclausetail.length; j++) {
173 									if (!xclausetail[j].equals(yclausetail[j])) {
174 										return false;
175 									}
176 
177 								}
178 
179 								return true;
180 							}
181 						}
182 					}
183 				} catch (PrologException e) {
184 					getLogger().error(getClass(), INDICATOR_NOT_FOUND, e);
185 				}
186 			}
187 		}
188 		return false;
189 	}
190 
191 	public void asserta(String stringClause) {
192 		try {
193 			Term term = new Parser(stringClause).nextTerm(false);
194 			asserta(BuiltIn.convertTermToClause(term));
195 		} catch (PrologException e) {
196 			getLogger().error(getClass(), SYNTAX_ERROR + stringClause, e);
197 		}
198 	}
199 
200 	@Override
201 	public void asserta(PrologTerm term) {
202 		asserta("" + term + "");
203 	}
204 
205 	public void asserta(PrologTerm head, PrologTerm... body) {
206 		Struct h = fromTerm(head, Struct.class);
207 		Struct[] b = new Struct[body.length];
208 		for (int i = 0; i < body.length; i++) {
209 			b[i] = fromTerm(body[i], Struct.class);
210 		}
211 		Struct o = fromTerm(head, body, Struct.class);
212 		asserta(new Clause(b, h, o));
213 	}
214 
215 	private void asserta(Clause clause) {
216 		if (!exist(clause)) {
217 			try {
218 				engine.assertA(clause);
219 			} catch (PrologException e) {
220 				getLogger().error(getClass(), RUNTIME_ERROR, e);
221 			}
222 		}
223 	}
224 
225 	public void assertz(String stringClause) {
226 		try {
227 			Term term = new Parser(stringClause).nextTerm(false);
228 			assertz(BuiltIn.convertTermToClause(term));
229 		} catch (PrologException e) {
230 			getLogger().error(getClass(), SYNTAX_ERROR + stringClause, e);
231 		}
232 	}
233 
234 	@Override
235 	public void assertz(PrologTerm term) {
236 		assertz("" + term + "");
237 	}
238 
239 	public void assertz(PrologTerm head, PrologTerm... body) {
240 		Struct h = fromTerm(head, Struct.class);
241 		Struct[] b = new Struct[body.length];
242 		for (int i = 0; i < body.length; i++) {
243 			b[i] = fromTerm(body[i], Struct.class);
244 		}
245 		Struct o = fromTerm(head, body, Struct.class);
246 		assertz(new Clause(b, h, o));
247 	}
248 
249 	private void assertz(Clause clause) {
250 		if (!exist(clause)) {
251 			try {
252 				engine.assertZ(clause);
253 			} catch (PrologException e) {
254 				getLogger().error(getClass(), RUNTIME_ERROR, e);
255 			}
256 		}
257 	}
258 
259 	public boolean clause(String stringClause) {
260 		try {
261 			Term term = new Parser(stringClause).nextTerm(false);
262 			return clause(BuiltIn.convertTermToClause(term));
263 		} catch (PrologException e) {
264 			getLogger().error(getClass(), SYNTAX_ERROR + stringClause, e);
265 		}
266 		return false;
267 	}
268 
269 	@Override
270 	public boolean clause(PrologTerm term) {
271 		return clause("" + term + "");
272 	}
273 
274 	public boolean clause(PrologTerm head, PrologTerm... body) {
275 		Struct h = fromTerm(head, Struct.class);
276 		Struct[] b = new Struct[body.length];
277 		for (int i = 0; i < body.length; i++) {
278 			b[i] = fromTerm(body[i], Struct.class);
279 		}
280 		Struct o = fromTerm(head, body, Struct.class);
281 		return clause(new Clause(b, h, o));
282 	}
283 
284 	private boolean clause(Clause clause) {
285 		String key = clause.head.name + "/" + clause.head.arity;
286 		Iterator<?> i = engine.dynamicPredicateIndicators();
287 		while (i.hasNext()) {
288 			String predIndicator = (String) i.next();
289 			if (predIndicator.equals(key)) {
290 				try {
291 					List<?> list = engine.find(predIndicator);
292 					for (Object object : list) {
293 						if (object instanceof Clause) {
294 							Clause c = (Clause) object;
295 							if (Prolog.match(c.original, clause.original)) {
296 								return true;
297 							}
298 						}
299 					}
300 				} catch (PrologException e) {
301 					getLogger().error(getClass(), INDICATOR_NOT_FOUND + predIndicator, e);
302 				}
303 			}
304 		}
305 		return false;
306 	}
307 
308 	public void retract(String stringClause) {
309 		try {
310 			Term term = new Parser(stringClause).nextTerm(false);
311 			retract(BuiltIn.convertTermToClause(term));
312 		} catch (PrologException e) {
313 			getLogger().error(getClass(), SYNTAX_ERROR + stringClause, e);
314 		}
315 	}
316 
317 	@Override
318 	public void retract(PrologTerm term) {
319 		retract("" + term + "");
320 	}
321 
322 	public void retract(PrologTerm head, PrologTerm... body) {
323 		Struct h = fromTerm(head, Struct.class);
324 		Struct[] b = new Struct[body.length];
325 		for (int i = 0; i < body.length; i++) {
326 			b[i] = fromTerm(body[i], Struct.class);
327 		}
328 		Struct o = fromTerm(head, body, Struct.class);
329 		retract(new Clause(b, h, o));
330 	}
331 
332 	private void retract(Clause clause) {
333 		try {
334 			engine.retract(clause.original);
335 		} catch (PrologException e) {
336 			getLogger().error(getClass(), RUNTIME_ERROR, e);
337 		}
338 	}
339 
340 	@Override
341 	public PrologQuery query(PrologTerm goal) {
342 		return new JTrologQuery(this, goal);
343 	}
344 
345 	public PrologQuery query(String stringQuery) {
346 		return new JTrologQuery(this, stringQuery);
347 	}
348 
349 	public PrologQuery query(PrologTerm[] terms) {
350 		return new JTrologQuery(this, terms);
351 	}
352 
353 	public PrologQuery query(PrologTerm term, PrologTerm... terms) {
354 		return new JTrologQuery(this, term, terms);
355 	}
356 
357 	public void operator(int priority, String specifier, String operator) {
358 		engine.opNew(operator, specifier, priority);
359 	}
360 
361 	public boolean currentPredicate(String functor, int arity) {
362 		String key = Parser.wrapAtom(functor) + "/" + arity;
363 
364 		// supported built-ins
365 		boolean isBuiltin = engine.hasPrimitive(key) || engine.hasPrimitiveExp(key);
366 
367 		// user defined predicates
368 		if (!isBuiltin) {
369 			try {
370 				if (!engine.find(key).isEmpty()) {
371 					return true;
372 				}
373 			} catch (PrologException e) {
374 				getLogger().error(getClass(), PrologLogger.INDICATOR_NOT_FOUND + key, e);
375 			}
376 		}
377 
378 		// not defined
379 		return isBuiltin;
380 	}
381 
382 	public boolean currentOperator(int priority, String specifier, String operator) {
383 		return currentOperators().contains(new JTrologOperator(priority, specifier, operator));
384 	}
385 
386 	public Set<PrologOperator> currentOperators() {
387 		return JTrologUtil.getOperatorSet(engine);
388 	}
389 
390 	public Iterator<PrologClause> iterator() {
391 		Collection<PrologClause> cls = new LinkedList<PrologClause>();
392 		Parser parser = new Parser(engine.getTheory());
393 		for (Iterator<?> iterator = parser.iterator(); iterator.hasNext();) {
394 			Term term = (Term) iterator.next();
395 			if (term instanceof Struct) {
396 				Struct struct = (Struct) term;
397 				if (struct.name.equals(":-") && struct.arity == 2) {
398 					PrologTerm head = toTerm(struct.getArg(0), PrologTerm.class);
399 					PrologTerm body = toTerm(struct.getArg(1), PrologTerm.class);
400 					cls.add(new JTrologClause(provider, head, body, false, false, false));
401 				} else {
402 					PrologTerm head = toTerm(struct, PrologTerm.class);
403 					cls.add(new JTrologClause(provider, head, false, false, false));
404 				}
405 			}
406 		}
407 		return new PrologProgramIterator(cls);
408 	}
409 
410 	public int getProgramSize() {
411 		int counter = 0;
412 		Iterator<?> i = engine.dynamicPredicateIndicators();
413 		while (i.hasNext()) {
414 			String predIndicator = (String) i.next();
415 			try {
416 				List<?> list = engine.find(predIndicator);
417 				counter += list.size();
418 			} catch (PrologException e) {
419 				getLogger().error(getClass(), PrologLogger.INDICATOR_NOT_FOUND + predIndicator, e);
420 			}
421 		}
422 		return counter;
423 	}
424 
425 	@Override
426 	public PrologProgram getProgram() {
427 		return new JTrologProgram(this);
428 	}
429 
430 	public Set<PrologIndicator> getPredicates() {
431 		Set<PrologIndicator> predicates = new HashSet<PrologIndicator>();
432 		Iterator<?> i = engine.dynamicPredicateIndicators();
433 		while (i.hasNext()) {
434 			String predIndicator = (String) i.next();
435 			try {
436 				List<?> list = engine.find(predIndicator);
437 				for (Object object : list) {
438 					if (object instanceof Clause) {
439 						Clause clause = (Clause) object;
440 						String functor = clause.head.name;
441 						int arity = clause.head.arity;
442 						JTrologIndicator p = new JTrologIndicator(functor, arity);
443 						predicates.add(p);
444 					}
445 				}
446 			} catch (PrologException e) {
447 				getLogger().error(getClass(), PrologLogger.INDICATOR_NOT_FOUND + predIndicator, e);
448 			}
449 		}
450 		return predicates;
451 	}
452 
453 	public Set<PrologIndicator> getBuiltIns() {
454 		Iterator<?> libraries = engine.getCurrentLibraries();
455 		Set<PrologIndicator> builtins = new HashSet<PrologIndicator>();
456 		while (libraries.hasNext()) {
457 			Object object = libraries.next();
458 			if (object instanceof Library) {
459 				Library library = (Library) object;
460 				Class<? extends Library> c = library.getClass();
461 				Method[] methods = c.getDeclaredMethods();
462 				String regex = "\\.|\\?|#|[a-z][A-Za-z0-9_]*_[0-9]+";
463 				for (Method method1 : methods) {
464 					String method = method1.getName();
465 					if (method.matches(regex)) {
466 						int j = method.lastIndexOf('_');
467 						String f = method.substring(0, j);
468 						int a = Integer.parseInt(method.substring(j + 1));
469 						builtins.add(new JTrologIndicator(f, a));
470 					}
471 				}
472 			}
473 		}
474 		return builtins;
475 	}
476 
477 	public String getLicense() {
478 		return Licenses.NO_SPECIFIED;
479 	}
480 
481 	public String getVersion() {
482 		return JTrolog.VERSION;
483 	}
484 
485 	public final String getVendor() {
486 		return JTrolog.NAME;
487 	}
488 
489 	public String getName() {
490 		return JTrolog.NAME;
491 	}
492 
493 	@Override
494 	public int hashCode() {
495 		final int prime = 31;
496 		int result = 1;
497 		result = prime * result + ((engine == null) ? 0 : engine.hashCode());
498 		return result;
499 	}
500 
501 	@Override
502 	public boolean equals(Object obj) {
503 		if (this == obj)
504 			return true;
505 		if (obj == null)
506 			return false;
507 		if (getClass() != obj.getClass())
508 			return false;
509 		JTrologEngine other = (JTrologEngine) obj;
510 		return engine != null && other.engine != null;
511 	}
512 
513 	public void dispose() {
514 		if (engine != null) {
515 			engine.clearTheory();
516 		}
517 	}
518 
519 	public final List<String> verify() {
520 		return Arrays.asList("OK");
521 	}
522 
523 }