View Javadoc

1   /*
2    * #%L
3    * prolobjectlink-jpi-jpl7
4    * %%
5    * Copyright (C) 2019 Prolobjectlink Project
6    * %%
7    * Redistribution and use in source and binary forms, with or without
8    * modification, are permitted provided that the following conditions are met:
9    * 
10   * 1. Redistributions of source code must retain the above copyright notice,
11   *    this list of conditions and the following disclaimer.
12   * 2. Redistributions in binary form must reproduce the above copyright notice,
13   *    this list of conditions and the following disclaimer in the documentation
14   *    and/or other materials provided with the distribution.
15   * 
16   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17   * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19   * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
20   * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22   * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23   * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24   * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26   * POSSIBILITY OF SUCH DAMAGE.
27   * #L%
28   */
29  package io.github.prolobjectlink.prolog.jpl7;
30  
31  import static io.github.prolobjectlink.prolog.PrologLogger.IO;
32  
33  import java.io.File;
34  import java.io.FileNotFoundException;
35  import java.io.FileOutputStream;
36  import java.io.IOException;
37  import java.io.PrintWriter;
38  import java.io.Reader;
39  import java.util.ArrayList;
40  import java.util.HashSet;
41  import java.util.Iterator;
42  import java.util.List;
43  import java.util.Set;
44  
45  import org.jpl7.Atom;
46  import org.jpl7.Query;
47  import org.jpl7.Term;
48  import org.jpl7.Util;
49  
50  import io.github.prolobjectlink.prolog.AbstractEngine;
51  import io.github.prolobjectlink.prolog.ArrayIterator;
52  import io.github.prolobjectlink.prolog.PrologClause;
53  import io.github.prolobjectlink.prolog.PrologEngine;
54  import io.github.prolobjectlink.prolog.PrologIndicator;
55  import io.github.prolobjectlink.prolog.PrologOperator;
56  import io.github.prolobjectlink.prolog.PrologProgram;
57  import io.github.prolobjectlink.prolog.PrologProvider;
58  import io.github.prolobjectlink.prolog.PrologQuery;
59  import io.github.prolobjectlink.prolog.PrologTerm;
60  import io.github.prolobjectlink.prolog.PrologTermType;
61  
62  /**
63   * 
64   * @author Jose Zalacain
65   * @since 1.0
66   */
67  public abstract class JplEngine extends AbstractEngine implements PrologEngine {
68  
69  	// used only for findall list result
70  	private static final String KEY = "X";
71  
72  	// JPL use for fact clauses true prolog term
73  	private static final Term BODY = new Atom("true");
74  
75  	// cache file in OS temporal directory
76  	private static String cache = null;
77  
78  	// parser to obtain terms from text
79  	private final JplParser parser = new JplParser();
80  
81  	// main memory prolog program
82  	private JplProgram program = new JplProgram();
83  
84  	// formulated string for < consult(cache), >
85  	private static String consultCacheComma;
86  	static {
87  		try {
88  			File f = File.createTempFile("prolobjectlink-jpi-jpl7-cache-", ".pl");
89  			cache = f.getCanonicalPath().replace(File.separatorChar, '/');
90  			consultCacheComma = "consult('" + cache + "'),";
91  		} catch (IOException e) {
92  			JplProvider.logger.error(JplEngine.class, IO, e);
93  		}
94  	}
95  
96  	protected JplEngine(PrologProvider provider) {
97  		super(provider);
98  	}
99  	
100 	protected JplEngine(PrologProvider provider, String path) {
101 		super(provider);
102 		consult(path);
103 	}
104 
105 	public final void consult(String path) {
106 		program = parser.parseProgram(path);
107 		persist(cache);
108 	}
109 
110 	public final void consult(Reader reader) {
111 		program = parser.parseProgram(reader);
112 		persist(cache);
113 	}
114 
115 	public final void include(String path) {
116 		program.add(parser.parseProgram(path));
117 		persist(cache);
118 	}
119 
120 	public final void include(Reader reader) {
121 		program.add(parser.parseProgram(reader));
122 		persist(cache);
123 	}
124 
125 	public final void persist(String path) {
126 		PrintWriter writer = null;
127 		try {
128 			writer = new PrintWriter(new FileOutputStream(path, false));
129 			writer.print(program);
130 		} catch (FileNotFoundException e) {
131 			getLogger().error(getClass(), IO + cache, e);
132 		} finally {
133 			if (writer != null) {
134 				writer.close();
135 			}
136 		}
137 	}
138 
139 	public final void abolish(String functor, int arity) {
140 		program.removeAll(functor, arity);
141 		persist(cache);
142 	}
143 
144 	public final void asserta(String stringClause) {
145 		asserta(Util.textToTerm(stringClause));
146 	}
147 
148 	public final void asserta(PrologTerm term) {
149 		asserta(fromTerm(term, Term.class));
150 	}
151 
152 	public final void asserta(PrologTerm head, PrologTerm... body) {
153 		asserta(fromTerm(head, body, Term.class));
154 	}
155 
156 	private void asserta(Term t) {
157 		program.push(t);
158 		persist(cache);
159 	}
160 
161 	public final void assertz(String stringClause) {
162 		assertz(Util.textToTerm(stringClause));
163 	}
164 
165 	public final void assertz(PrologTerm term) {
166 		assertz(fromTerm(term, Term.class));
167 	}
168 
169 	public final void assertz(PrologTerm head, PrologTerm... body) {
170 		assertz(fromTerm(head, body, Term.class));
171 	}
172 
173 	private void assertz(Term t) {
174 		program.add(t);
175 		persist(cache);
176 	}
177 
178 	public final boolean clause(String stringClause) {
179 		return clause(Util.textToTerm(stringClause));
180 	}
181 
182 	public final boolean clause(PrologTerm term) {
183 		return clause(fromTerm(term, Term.class));
184 	}
185 
186 	public final boolean clause(PrologTerm head, PrologTerm... body) {
187 		return clause(fromTerm(head, body, Term.class));
188 	}
189 
190 	private boolean clause(Term t) {
191 		Term h = t;
192 		Term b = BODY;
193 		if (t.hasFunctor(":-", 2)) {
194 			h = t.arg(1);
195 			b = t.arg(2);
196 		}
197 		return new JplQuery(
198 
199 				this, cache, "clause(" + h + "," + b + ")"
200 
201 		).hasSolution();
202 	}
203 
204 	public final void retract(String stringClause) {
205 		retract(Util.textToTerm(stringClause));
206 	}
207 
208 	public final void retract(PrologTerm term) {
209 		retract(fromTerm(term, Term.class));
210 	}
211 
212 	public final void retract(PrologTerm head, PrologTerm... body) {
213 		retract(provider.fromTerm(head, body, Term.class));
214 	}
215 
216 	private void retract(Term t) {
217 		program.remove(t);
218 		persist(cache);
219 	}
220 
221 	public final PrologQuery query(String stringQuery) {
222 		return new JplQuery(this, cache, stringQuery);
223 	}
224 
225 	public final PrologQuery query(PrologTerm term) {
226 		StringBuilder buffer = new StringBuilder();
227 		buffer.append("" + term + ".");
228 		return query("" + buffer + "");
229 	}
230 
231 	public final PrologQuery query(PrologTerm[] terms) {
232 		Iterator<PrologTerm> i = new ArrayIterator<PrologTerm>(terms);
233 		StringBuilder buffer = new StringBuilder();
234 		while (i.hasNext()) {
235 			buffer.append(i.next());
236 			if (i.hasNext()) {
237 				buffer.append(',');
238 			}
239 		}
240 		buffer.append(".");
241 		return query("" + buffer + "");
242 	}
243 
244 	public final PrologQuery query(PrologTerm term, PrologTerm... terms) {
245 		Iterator<PrologTerm> i = new ArrayIterator<PrologTerm>(terms);
246 		StringBuilder buffer = new StringBuilder();
247 		buffer.append("" + term + "");
248 		while (i.hasNext()) {
249 			buffer.append(',');
250 			buffer.append(i.next());
251 		}
252 		buffer.append(".");
253 		return query("" + buffer + "");
254 	}
255 
256 	public final void operator(int priority, String specifier, String operator) {
257 		new Query(consultCacheComma + "op(" + priority + "," + specifier + ", " + operator + ")").hasSolution();
258 	}
259 
260 	public final boolean currentPredicate(String functor, int arity) {
261 		String x = functor;
262 		if (x.startsWith("'") && x.endsWith("'")) {
263 			x = x.substring(1, x.length() - 1);
264 		}
265 		return getPredicates().contains(new JplIndicator(x, arity));
266 	}
267 
268 	public final boolean currentOperator(int priority, String specifier, String operator) {
269 		return new Query(consultCacheComma + "current_op(" + priority + "," + specifier + ", " + operator + ")")
270 				.hasSolution();
271 	}
272 
273 	public final Set<PrologOperator> currentOperators() {
274 		Set<PrologOperator> operators = new HashSet<PrologOperator>();
275 		String opQuery = consultCacheComma + "findall(P/S/O,current_op(P,S,O)," + KEY + ")";
276 		Query query = new Query(opQuery);
277 		if (query.hasSolution()) {
278 			Term term = query.oneSolution().get(KEY);
279 			Term[] termArray = term.toTermArray();
280 			for (Term t : termArray) {
281 				Term prio = t.arg(1).arg(1);
282 				Term pos = t.arg(1).arg(2);
283 				Term op = t.arg(2);
284 
285 				int p = prio.intValue();
286 				String s = pos.name();
287 				String n = op.name();
288 
289 				PrologOperator o = new JplOperator(p, s, n);
290 				operators.add(o);
291 			}
292 		}
293 		query.close();
294 		return operators;
295 	}
296 
297 	public final int getProgramSize() {
298 		return program.size();
299 	}
300 
301 	public final PrologProgram getProgram() {
302 		return new JplScript(this);
303 	}
304 
305 	public final Set<PrologIndicator> getPredicates() {
306 		Set<PrologIndicator> indicators = new HashSet<PrologIndicator>();
307 		String opQuery = consultCacheComma + "findall(X/Y,current_predicate(X/Y)," + KEY + ")";
308 		Query query = new Query(opQuery);
309 		if (query.hasSolution()) {
310 			Term term = query.oneSolution().get(KEY);
311 			Term[] termArray = term.toTermArray();
312 			for (Term t : termArray) {
313 				Term f = t.arg(1);
314 				Term a = t.arg(2);
315 
316 				int arity = a.intValue();
317 				String functor = f.name();
318 
319 				JplIndicator pi = new JplIndicator(functor, arity);
320 				indicators.add(pi);
321 			}
322 		}
323 		return indicators;
324 	}
325 
326 	public final Set<PrologIndicator> getBuiltIns() {
327 		Set<PrologIndicator> indicators = new HashSet<PrologIndicator>();
328 		String opQuery = consultCacheComma + "findall(X/Y,current_predicate(X/Y)," + KEY + ")";
329 		Query query = new Query(opQuery);
330 		if (query.hasSolution()) {
331 			Term term = query.oneSolution().get(KEY);
332 			Term[] termArray = term.toTermArray();
333 			for (Term t : termArray) {
334 				Term f = t.arg(1);
335 				Term a = t.arg(2);
336 
337 				int arity = a.intValue();
338 				String functor = f.name();
339 
340 				JplIndicator pi = new JplIndicator(functor, arity);
341 				indicators.add(pi);
342 			}
343 		}
344 		Set<PrologClause> clauses = getProgramClauses();
345 		for (PrologClause prologClause : clauses) {
346 			PrologIndicator pi = prologClause.getPrologIndicator();
347 			if (indicators.contains(pi)) {
348 				indicators.remove(pi);
349 			}
350 		}
351 		return indicators;
352 	}
353 
354 	public final Iterator<PrologClause> iterator() {
355 		List<PrologClause> cls = new ArrayList<PrologClause>();
356 		for (List<Term> family : program.getClauses().values()) {
357 			for (Term clause : family) {
358 				if (clause.hasFunctor(":-", 2)) {
359 					PrologTerm head = toTerm(clause.arg(1), PrologTerm.class);
360 					PrologTerm body = toTerm(clause.arg(2), PrologTerm.class);
361 					if (body.getType() != PrologTermType.TRUE_TYPE) {
362 						cls.add(new JplClause(provider, head, body, false, false, false));
363 					} else {
364 						cls.add(new JplClause(provider, head, false, false, false));
365 					}
366 				} else {
367 					cls.add(new JplClause(provider, toTerm(clause, PrologTerm.class), false, false, false));
368 				}
369 			}
370 		}
371 		return new PrologProgramIterator(cls);
372 	}
373 
374 	public final void dispose() {
375 		File c = new File(cache);
376 		PrintWriter writer = null;
377 		try {
378 			writer = new PrintWriter(new FileOutputStream(cache, false));
379 			writer.print("");
380 		} catch (FileNotFoundException e) {
381 			getLogger().error(getClass(), IO + cache, e);
382 		} finally {
383 			if (writer != null) {
384 				writer.close();
385 			}
386 		}
387 		c.deleteOnExit();
388 		program.clear();
389 	}
390 
391 	public final String getCache() {
392 		return cache;
393 	}
394 
395 	@Override
396 	public int hashCode() {
397 		final int prime = 31;
398 		int result = super.hashCode();
399 		result = prime * result + ((program == null) ? 0 : program.hashCode());
400 		return result;
401 	}
402 
403 	@Override
404 	public boolean equals(Object obj) {
405 		if (this == obj)
406 			return true;
407 		if (!super.equals(obj))
408 			return false;
409 		if (getClass() != obj.getClass())
410 			return false;
411 		JplEngine other = (JplEngine) obj;
412 		if (program == null) {
413 			if (other.program != null)
414 				return false;
415 		} else if (!program.equals(other.program)) {
416 			return false;
417 		}
418 		return true;
419 	}
420 
421 }