View Javadoc

1   /*
2    * #%L
3    * prolobjectlink-jpi-tuprolog
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.tuprolog;
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.IO;
27  import static io.github.prolobjectlink.prolog.PrologLogger.SYNTAX_ERROR;
28  
29  import java.io.BufferedReader;
30  import java.io.FileInputStream;
31  import java.io.FileNotFoundException;
32  import java.io.IOException;
33  import java.io.PrintWriter;
34  import java.io.Reader;
35  import java.util.Arrays;
36  import java.util.Collection;
37  import java.util.HashSet;
38  import java.util.Iterator;
39  import java.util.LinkedList;
40  import java.util.List;
41  import java.util.Set;
42  
43  import alice.tuprolog.Int;
44  import alice.tuprolog.InvalidTheoryException;
45  import alice.tuprolog.Library;
46  import alice.tuprolog.MalformedGoalException;
47  import alice.tuprolog.Operator;
48  import alice.tuprolog.Parser;
49  import alice.tuprolog.PrimitiveInfo;
50  import alice.tuprolog.Prolog;
51  import alice.tuprolog.Struct;
52  import alice.tuprolog.Term;
53  import alice.tuprolog.Theory;
54  import alice.tuprolog.TheoryManager;
55  import io.github.prolobjectlink.prolog.AbstractEngine;
56  import io.github.prolobjectlink.prolog.Licenses;
57  import io.github.prolobjectlink.prolog.PrologClause;
58  import io.github.prolobjectlink.prolog.PrologEngine;
59  import io.github.prolobjectlink.prolog.PrologIndicator;
60  import io.github.prolobjectlink.prolog.PrologOperator;
61  import io.github.prolobjectlink.prolog.PrologProgram;
62  import io.github.prolobjectlink.prolog.PrologProvider;
63  import io.github.prolobjectlink.prolog.PrologQuery;
64  import io.github.prolobjectlink.prolog.PrologTerm;
65  import io.github.prolobjectlink.prolog.SyntaxError;
66  
67  /**
68   * 
69   * @author Jose Zalacain
70   * @since 1.0
71   */
72  public class TuPrologEngine extends AbstractEngine implements PrologEngine {
73  
74  	final Prolog engine;
75  
76  	protected TuPrologEngine(PrologProvider provider, Prolog engine) {
77  		super(provider);
78  		this.engine = engine;
79  	}
80  
81  	public void consult(String path) {
82  		try {
83  			Theory theory = new Theory(new FileInputStream(path));
84  			engine.setTheory(theory);
85  		} catch (FileNotFoundException e) {
86  			getLogger().warn(getClass(), FILE_NOT_FOUND + path, e);
87  			getLogger().info(getClass(), DONT_WORRY + path);
88  		} catch (IOException e) {
89  			getLogger().warn(getClass(), IO + path, e);
90  			getLogger().info(getClass(), DONT_WORRY + path);
91  		} catch (InvalidTheoryException e) {
92  			getLogger().error(getClass(), SYNTAX_ERROR + path, e);
93  		}
94  	}
95  
96  	public void consult(Reader reader) {
97  		BufferedReader bfr = new BufferedReader(reader);
98  		StringBuilder script = new StringBuilder();
99  		try {
100 			String line = bfr.readLine();
101 			while (line != null) {
102 				script.append(line);
103 				script.append("\n");
104 				line = bfr.readLine();
105 			}
106 			engine.setTheory(new Theory("" + script + ""));
107 		} catch (InvalidTheoryException e) {
108 			getLogger().error(getClass(), SYNTAX_ERROR + script, e);
109 		} catch (IOException e) {
110 			getLogger().warn(getClass(), IO + script, e);
111 		}
112 	}
113 
114 	public void include(String path) {
115 		TheoryManager manager = engine.getTheoryManager();
116 		try {
117 			manager.consult(new Theory(new FileInputStream(path)), true, null);
118 		} catch (FileNotFoundException e) {
119 			getLogger().error(getClass(), FILE_NOT_FOUND + path, e);
120 		} catch (IOException e) {
121 			getLogger().error(getClass(), IO + path, e);
122 		} catch (InvalidTheoryException e) {
123 			getLogger().error(getClass(), SYNTAX_ERROR + path, e);
124 		}
125 	}
126 
127 	public void include(Reader reader) {
128 		TheoryManager manager = engine.getTheoryManager();
129 		BufferedReader bfr = new BufferedReader(reader);
130 		StringBuilder script = new StringBuilder();
131 		try {
132 			String line = bfr.readLine();
133 			while (line != null) {
134 				script.append(line);
135 				script.append("\n");
136 				line = bfr.readLine();
137 			}
138 			manager.consult(new Theory("" + script + ""), true, null);
139 		} catch (InvalidTheoryException e) {
140 			getLogger().error(getClass(), SYNTAX_ERROR + script, e);
141 		} catch (IOException e) {
142 			getLogger().warn(getClass(), IO + script, e);
143 		}
144 	}
145 
146 	public void persist(String path) {
147 		PrintWriter writer = null;
148 		try {
149 			writer = new PrintWriter(path);
150 			writer.write(engine.getTheoryManager().getTheory(true));
151 		} catch (IOException e) {
152 			getLogger().warn(getClass(), IO + path, e);
153 			getLogger().info(getClass(), DONT_WORRY + path);
154 		} finally {
155 			if (writer != null) {
156 				writer.close();
157 			}
158 		}
159 	}
160 
161 	public void abolish(String functor, int arity) {
162 		Struct pi = new Struct("/", new Struct(functor), new Int(arity));
163 		engine.getTheoryManager().abolish(pi);
164 	}
165 
166 	public void asserta(String stringClause) {
167 		TheoryManager manager = engine.getTheoryManager();
168 		if (stringClause != null && !clause(stringClause)) {
169 			manager.assertA((Struct) Term.createTerm(stringClause), true, null, false);
170 		}
171 	}
172 
173 	public void asserta(PrologTerm term) {
174 		TheoryManager manager = engine.getTheoryManager();
175 		if (term != null && !clause(term)) {
176 			manager.assertA(fromTerm(term, Struct.class), true, null, false);
177 		}
178 	}
179 
180 	public void asserta(PrologTerm head, PrologTerm... body) {
181 		boolean hasBody = body != null && body.length > 0;
182 		if (hasBody ? !clause(head, body) : !clause(head)) {
183 			TheoryManager manager = engine.getTheoryManager();
184 			manager.assertA(fromTerm(head, body, Struct.class), true, null, false);
185 		}
186 	}
187 
188 	public void assertz(String stringClause) {
189 		TheoryManager manager = engine.getTheoryManager();
190 		if (stringClause != null && !clause(stringClause)) {
191 			manager.assertZ((Struct) Term.createTerm(stringClause), true, null, false);
192 		}
193 	}
194 
195 	public void assertz(PrologTerm term) {
196 		TheoryManager manager = engine.getTheoryManager();
197 		if (term != null && !clause(term)) {
198 			manager.assertZ(fromTerm(term, Struct.class), true, null, false);
199 		}
200 	}
201 
202 	public void assertz(PrologTerm head, PrologTerm... body) {
203 		boolean hasBody = body != null && body.length > 0;
204 		if (hasBody ? !clause(head, body) : !clause(head)) {
205 			TheoryManager manager = engine.getTheoryManager();
206 			manager.assertZ(fromTerm(head, body, Struct.class), true, null, false);
207 		}
208 	}
209 
210 	public boolean clause(String stringClause) {
211 		Term toBeMatched = Term.createTerm(stringClause);
212 		TheoryManager manager = engine.getTheoryManager();
213 		try {
214 			Theory theory = new Theory(manager.getTheory(true));
215 			Iterator<? extends Term> iterator = theory.iterator(engine);
216 			while (iterator.hasNext()) {
217 				Term term = iterator.next();
218 				if (term.match(toBeMatched)) {
219 					return true;
220 				}
221 			}
222 		} catch (InvalidTheoryException e) {
223 			getLogger().error(getClass(), SYNTAX_ERROR, e);
224 		}
225 		return false;
226 	}
227 
228 	public boolean clause(PrologTerm head) {
229 		TheoryManager manager = engine.getTheoryManager();
230 		try {
231 			Theory theory = new Theory(manager.getTheory(true));
232 			Iterator<? extends Term> iterator = theory.iterator(engine);
233 			while (iterator.hasNext()) {
234 				Term term = iterator.next();
235 				if (term.match(fromTerm(head, Struct.class))) {
236 					return true;
237 				}
238 			}
239 		} catch (InvalidTheoryException e) {
240 			getLogger().error(getClass(), SYNTAX_ERROR, e);
241 		}
242 		return false;
243 	}
244 
245 	public boolean clause(PrologTerm head, PrologTerm... body) {
246 		TheoryManager manager = engine.getTheoryManager();
247 		try {
248 			Theory theory = new Theory(manager.getTheory(true));
249 			Iterator<? extends Term> iterator = theory.iterator(engine);
250 			while (iterator.hasNext()) {
251 				Term term = iterator.next();
252 				if (term.match(fromTerm(head, body, Struct.class))) {
253 					return true;
254 				}
255 			}
256 		} catch (InvalidTheoryException e) {
257 			getLogger().error(getClass(), SYNTAX_ERROR, e);
258 		}
259 		return false;
260 	}
261 
262 	public void retract(String stringClause) {
263 		try {
264 			engine.solve("retract(" + stringClause + ").");
265 		} catch (MalformedGoalException e) {
266 			throw new SyntaxError("Syntax error", e);
267 		}
268 	}
269 
270 	public void retract(PrologTerm head) {
271 		retract("" + fromTerm(head, Struct.class) + "");
272 	}
273 
274 	public void retract(PrologTerm head, PrologTerm... body) {
275 		retract("" + fromTerm(head, body, Struct.class) + "");
276 	}
277 
278 	public PrologQuery query(String stringQuery) {
279 		return new TuPrologQuery(this, stringQuery);
280 	}
281 
282 	public PrologQuery query(PrologTerm term) {
283 		return new TuPrologQuery(this, term);
284 	}
285 
286 	public PrologQuery query(PrologTerm[] terms) {
287 		return new TuPrologQuery(this, terms);
288 	}
289 
290 	public PrologQuery query(PrologTerm term, PrologTerm... terms) {
291 		return new TuPrologQuery(this, term, terms);
292 	}
293 
294 	public void operator(int priority, String specifier, String operator) {
295 		engine.getOperatorManager().opNew(operator, specifier, priority);
296 	}
297 
298 	public boolean currentPredicate(String functor, int arity) {
299 		String newFunctor = removeQuoted(functor);
300 		PrologIndicator pi = new TuPrologIndicator(newFunctor, arity);
301 		return currentPredicates().contains(pi);
302 	}
303 
304 	public boolean currentOperator(int priority, String specifier, String operator) {
305 		return engine.getOperatorManager().opPrio(operator, specifier) == priority;
306 	}
307 
308 	public Set<PrologOperator> currentOperators() {
309 		List<Operator> operatorsList = engine.getOperatorManager().getOperators();
310 		Set<PrologOperator> operators = new HashSet<PrologOperator>(operatorsList.size());
311 		for (Operator operator : operatorsList) {
312 			String name = operator.name;
313 			int priority = operator.prio;
314 			String specifier = operator.type;
315 			PrologOperator op = new TuPrologOperator(priority, specifier, name);
316 			operators.add(op);
317 		}
318 		return operators;
319 	}
320 
321 	public Iterator<PrologClause> iterator() {
322 		Collection<PrologClause> cls = new LinkedList<PrologClause>();
323 		Parser parser = new Parser(engine.getTheoryManager().getTheory(true));
324 		for (Iterator<Term> iterator = parser.iterator(); iterator.hasNext();) {
325 			Term term = iterator.next();
326 			if (term instanceof Struct) {
327 				Struct struct = (Struct) term;
328 				if (struct.getName().equals(":-") && struct.getArity() == 2) {
329 					PrologTerm head = toTerm(struct.getArg(0), PrologTerm.class);
330 					PrologTerm body = toTerm(struct.getArg(1), PrologTerm.class);
331 					cls.add(new TuPrologClause(provider, head, body, false, false, false));
332 				} else {
333 					PrologTerm head = toTerm(struct, PrologTerm.class);
334 					cls.add(new TuPrologClause(provider, head, false, false, false));
335 				}
336 			}
337 		}
338 		return new PrologProgramIterator(cls);
339 	}
340 
341 	public int getProgramSize() {
342 		int counter = 0;
343 		Iterator<? extends Term> i = engine.getTheory().iterator(engine);
344 		while (i.hasNext()) {
345 			i.next();
346 			counter++;
347 		}
348 		return counter;
349 	}
350 
351 	@Override
352 	public PrologProgram getProgram() {
353 		return new TuPrologProgram(this);
354 	}
355 
356 	public Set<PrologIndicator> getPredicates() {
357 		Set<PrologIndicator> predicates = new HashSet<PrologIndicator>();
358 		TheoryManager manager = engine.getTheoryManager();
359 		try {
360 			Theory theory = new Theory(manager.getTheory(true));
361 			Iterator<? extends Term> iterator = theory.iterator(engine);
362 			while (iterator.hasNext()) {
363 				Term term = iterator.next();
364 				if (term instanceof Struct) {
365 					Struct struct = (Struct) term;
366 					int arity = struct.getArity();
367 					String functor = struct.getName();
368 					if (functor.equals(":-") && arity == 2) {
369 						Term head = struct.getArg(0);
370 						if (head instanceof Struct) {
371 							Struct headStruct = (Struct) head;
372 							arity = headStruct.getArity();
373 							functor = headStruct.getName();
374 							TuPrologIndicator pi = new TuPrologIndicator(functor, arity);
375 							predicates.add(pi);
376 						}
377 					} else {
378 						TuPrologIndicator pi = new TuPrologIndicator(functor, arity);
379 						predicates.add(pi);
380 					}
381 				}
382 			}
383 		} catch (InvalidTheoryException e) {
384 			getLogger().error(getClass(), SYNTAX_ERROR, e);
385 		}
386 
387 		return predicates;
388 	}
389 
390 	public Set<PrologIndicator> getBuiltIns() {
391 		String[] libraries = engine.getCurrentLibraries();
392 		Set<PrologIndicator> builtins = new HashSet<PrologIndicator>();
393 		for (String libraryName : libraries) {
394 			Library library = engine.getLibrary(libraryName);
395 			Collection<List<PrimitiveInfo>> c = library.getPrimitives().values();
396 			for (List<PrimitiveInfo> list : c) {
397 				for (PrimitiveInfo primitiveInfo : list) {
398 					String key = primitiveInfo.getKey();
399 					String functor = key.substring(0, key.lastIndexOf('/'));
400 					int arity = Integer.parseInt(key.substring(key.lastIndexOf('/') + 1));
401 					TuPrologIndicator pi = new TuPrologIndicator(functor, arity);
402 					builtins.add(pi);
403 				}
404 			}
405 		}
406 		return builtins;
407 	}
408 
409 	public String getLicense() {
410 		return Licenses.LGPL_V3;
411 	}
412 
413 	public String getVersion() {
414 		return TuProlog.VERSION;
415 	}
416 
417 	public final String getVendor() {
418 		return TuProlog.NAME;
419 	}
420 
421 	public String getName() {
422 		return TuProlog.NAME;
423 	}
424 
425 	@Override
426 	public int hashCode() {
427 		final int prime = 31;
428 		int result = 1;
429 		result = prime * result + ((engine == null) ? 0 : engine.hashCode());
430 		return result;
431 	}
432 
433 	@Override
434 	public boolean equals(Object obj) {
435 		if (this == obj)
436 			return true;
437 		if (obj == null)
438 			return false;
439 		if (getClass() != obj.getClass())
440 			return false;
441 		TuPrologEngine other = (TuPrologEngine) obj;
442 		// tu-prolog engine not override equals from object
443 		// current criteria is not null engine instances
444 		return engine != null && other.engine != null;
445 	}
446 
447 	public void dispose() {
448 		if (engine != null) {
449 			engine.clearTheory();
450 		}
451 	}
452 
453 	public final List<String> verify() {
454 		return Arrays.asList("OK");
455 	}
456 
457 }