1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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
58
59
60 public abstract class JplEngine extends AbstractEngine implements PrologEngine {
61
62
63 private static final String KEY = "X";
64
65
66 private static final Term BODY = new Atom("true");
67
68
69 private static String cache = null;
70
71
72 private final JplParser parser = new JplParser();
73
74
75 private JplProgram program = new JplProgram();
76
77
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 }