View Javadoc

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