View Javadoc

1   /*
2    * #%L
3    * prolobjectlink-jpi-jlog
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 General Public License as
9    * published by the Free Software Foundation, either version 3 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 Public License for more details.
16   * 
17   * You should have received a copy of the GNU General Public
18   * License along with this program.  If not, see
19   * <http://www.gnu.org/licenses/gpl-3.0.html>.
20   * #L%
21   */
22  package io.github.prolobjectlink.prolog.jlog;
23  
24  import static io.github.prolobjectlink.prolog.PrologLogger.ERROR_LOADING_BUILT_INS;
25  import static io.github.prolobjectlink.prolog.PrologLogger.FILE_NOT_FOUND;
26  import static io.github.prolobjectlink.prolog.PrologLogger.IO;
27  import static ubc.cs.JLog.Parser.pOperatorEntry.FX;
28  import static ubc.cs.JLog.Parser.pOperatorEntry.FY;
29  import static ubc.cs.JLog.Parser.pOperatorEntry.XF;
30  import static ubc.cs.JLog.Parser.pOperatorEntry.XFX;
31  import static ubc.cs.JLog.Parser.pOperatorEntry.XFY;
32  import static ubc.cs.JLog.Parser.pOperatorEntry.YF;
33  import static ubc.cs.JLog.Parser.pOperatorEntry.YFX;
34  
35  import java.io.FileNotFoundException;
36  import java.io.FileReader;
37  import java.io.FileWriter;
38  import java.io.IOException;
39  import java.io.PrintWriter;
40  import java.io.Reader;
41  import java.util.Arrays;
42  import java.util.Collection;
43  import java.util.Enumeration;
44  import java.util.HashSet;
45  import java.util.Iterator;
46  import java.util.LinkedList;
47  import java.util.List;
48  import java.util.Set;
49  import java.util.StringTokenizer;
50  
51  import io.github.prolobjectlink.prolog.AbstractEngine;
52  import io.github.prolobjectlink.prolog.Licenses;
53  import io.github.prolobjectlink.prolog.PrologClause;
54  import io.github.prolobjectlink.prolog.PrologEngine;
55  import io.github.prolobjectlink.prolog.PrologIndicator;
56  import io.github.prolobjectlink.prolog.PrologOperator;
57  import io.github.prolobjectlink.prolog.PrologProgram;
58  import io.github.prolobjectlink.prolog.PrologProvider;
59  import io.github.prolobjectlink.prolog.PrologQuery;
60  import io.github.prolobjectlink.prolog.PrologTerm;
61  import ubc.cs.JLog.Foundation.iNameArityStub;
62  import ubc.cs.JLog.Foundation.jKnowledgeBase;
63  import ubc.cs.JLog.Foundation.jPrologFileServices;
64  import ubc.cs.JLog.Foundation.jPrologServices;
65  import ubc.cs.JLog.Foundation.jRule;
66  import ubc.cs.JLog.Foundation.jRuleDefinitions;
67  import ubc.cs.JLog.Foundation.jUnifiedVector;
68  import ubc.cs.JLog.Parser.pGenericOperatorEntry;
69  import ubc.cs.JLog.Parser.pGenericPredicateEntry;
70  import ubc.cs.JLog.Parser.pOperatorEntry;
71  import ubc.cs.JLog.Parser.pOperatorRegistry;
72  import ubc.cs.JLog.Parser.pParseStream;
73  import ubc.cs.JLog.Parser.pPredicateOperatorEntry;
74  import ubc.cs.JLog.Parser.pPredicateRegistry;
75  import ubc.cs.JLog.Terms.iNameArity;
76  import ubc.cs.JLog.Terms.jBuiltinRule;
77  import ubc.cs.JLog.Terms.jPredicate;
78  import ubc.cs.JLog.Terms.jPredicateTerms;
79  
80  /**
81   * 
82   * @author Jose Zalacain
83   * @since 1.0
84   */
85  public class JLogEngine extends AbstractEngine implements PrologEngine {
86  
87  	final jPrologServices engine;
88  	private final jKnowledgeBase kb;
89  	private final pOperatorRegistry or;
90  	private final pPredicateRegistry pr;
91  
92  	private static final String BUILT_INS = "builtins";
93  
94  	private final pGenericPredicateEntry multifile = new pGenericPredicateEntry("multifile", 1, jMultifile.class);
95  //	private final pGenericOperatorEntry m = new pGenericOperatorEntry("multifile", type, priority, jMultifile.class);
96  
97  	protected JLogEngine(PrologProvider provider) {
98  		super(provider);
99  		kb = new jKnowledgeBase();
100 		or = new pOperatorRegistry();
101 		pr = new pPredicateRegistry();
102 		pr.addPredicate(multifile);
103 		engine = new jPrologServices(kb, pr, or);
104 		engine.setFileServices(new jPrologFileServices());
105 		try {
106 			engine.loadLibrary(BUILT_INS);
107 		} catch (IOException e) {
108 			getLogger().error(getClass(), ERROR_LOADING_BUILT_INS, e);
109 		}
110 	}
111 
112 	/**
113 	 * Find or Remove a give rule depending of boolean flag. If flag is true the
114 	 * rule will be removed. If flag is false just find the given rule. Return true
115 	 * if the rule was found, false otherwise.
116 	 * 
117 	 * @param rule       Rule to be found or removed
118 	 * @param toBeRemove Flag to indicate removal action
119 	 * @return true if the rule was found, false otherwise.
120 	 */
121 	private boolean clauseOrRetract(jRule rule, boolean toBeRemove) {
122 		String name = rule.getName();
123 		int arity = rule.getArity();
124 		jPredicate head = rule.getHead();
125 		jPredicateTerms body = rule.getBase();
126 		if (name.startsWith("'") && name.endsWith("'")) {
127 			name = name.substring(1, name.length() - 1);
128 		}
129 		iNameArity na = new iNameArityStub(name, arity);
130 		jRuleDefinitions rds = kb.getRuleDefinitionsMatch(na);
131 		if (rds != null && rds.size() > 0) {
132 			Enumeration<?> e = rds.enumRules();
133 			while (e.hasMoreElements()) {
134 				Object object = e.nextElement();
135 				if (object instanceof jRule) {
136 					jRule jRule = (jRule) object;
137 					jPredicate ruleHead = jRule.getHead();
138 					jPredicateTerms ruleBody = jRule.getBase();
139 					jUnifiedVector v = new jUnifiedVector();
140 					if (ruleHead.unify(head, v) && ruleBody.unify(body, v)) {
141 						if (toBeRemove) {
142 							rds.removeRule(jRule);
143 						}
144 						return true;
145 					}
146 				}
147 			}
148 		}
149 		return false;
150 	}
151 
152 	public void consult(String path) {
153 		try {
154 			kb.clearRules();
155 			FileReader fileReader = new FileReader(path);
156 			new pParseStream(fileReader, kb, pr, or).parseSource();
157 		} catch (FileNotFoundException e) {
158 			getLogger().error(getClass(), FILE_NOT_FOUND + path, e);
159 		}
160 	}
161 
162 	public void consult(Reader reader) {
163 		kb.clearRules();
164 		new pParseStream(reader, kb, pr, or).parseSource();
165 	}
166 
167 	public void include(String path) {
168 		try {
169 			FileReader fileReader = new FileReader(path);
170 			new pParseStream(fileReader, kb, pr, or).parseSource();
171 		} catch (FileNotFoundException e) {
172 			getLogger().error(getClass(), FILE_NOT_FOUND + path, e);
173 		}
174 	}
175 
176 	public void include(Reader reader) {
177 		new pParseStream(reader, kb, pr, or).parseSource();
178 	}
179 
180 	public void persist(String path) {
181 		PrintWriter writer = null;
182 		try {
183 			writer = new PrintWriter(new FileWriter(path));
184 			writer.print(JLogUtil.toString(engine));
185 			writer.flush();
186 		} catch (FileNotFoundException e) {
187 			getLogger().error(getClass(), FILE_NOT_FOUND + path, e);
188 		} catch (IOException e) {
189 			getLogger().error(getClass(), IO + path, e);
190 		} finally {
191 			assert writer != null;
192 			writer.close();
193 		}
194 	}
195 
196 	public void abolish(String functor, int arity) {
197 		functor = JLogUtil.removeQuotesIfNeed(functor);
198 		iNameArityStub na = new iNameArityStub(functor, arity);
199 		jRuleDefinitions definitions = kb.getRuleDefinitionsMatch(na);
200 		if (definitions != null) {
201 			definitions.clearRules();
202 		}
203 	}
204 
205 	public void asserta(String stringClause) {
206 		asserta(JLogUtil.toRule(stringClause, engine));
207 	}
208 
209 	@Override
210 	public void asserta(PrologTerm term) {
211 		asserta(JLogUtil.toRule(provider, term));
212 	}
213 
214 	public void asserta(PrologTerm head, PrologTerm... body) {
215 		asserta(JLogUtil.toRule(provider, head, body));
216 	}
217 
218 	private void asserta(jRule rule) {
219 		if (!clause(rule)) {
220 			kb.addRuleFirst(rule);
221 		}
222 	}
223 
224 	public void assertz(String stringClause) {
225 		assertz(JLogUtil.toRule(stringClause, engine));
226 	}
227 
228 	@Override
229 	public void assertz(PrologTerm term) {
230 		assertz(JLogUtil.toRule(provider, term));
231 	}
232 
233 	public void assertz(PrologTerm head, PrologTerm... body) {
234 		assertz(JLogUtil.toRule(provider, head, body));
235 	}
236 
237 	private void assertz(jRule rule) {
238 		if (!clause(rule)) {
239 			kb.addRuleLast(rule);
240 		}
241 	}
242 
243 	public boolean clause(String stringClause) {
244 		return clause(JLogUtil.toRule(stringClause, engine));
245 	}
246 
247 	@Override
248 	public boolean clause(PrologTerm term) {
249 		return clause(JLogUtil.toRule(provider, term));
250 	}
251 
252 	public boolean clause(PrologTerm head, PrologTerm... body) {
253 		return clause(JLogUtil.toRule(provider, head, body));
254 	}
255 
256 	private boolean clause(jRule rule) {
257 		return clauseOrRetract(rule, false);
258 	}
259 
260 	public void retract(String stringClause) {
261 		retract(JLogUtil.toRule(stringClause, engine));
262 	}
263 
264 	@Override
265 	public void retract(PrologTerm term) {
266 		retract(JLogUtil.toRule(provider, term));
267 	}
268 
269 	public void retract(PrologTerm head, PrologTerm... body) {
270 		retract(JLogUtil.toRule(provider, head, body));
271 	}
272 
273 	private void retract(jRule rule) {
274 		clauseOrRetract(rule, true);
275 	}
276 
277 	public PrologQuery query(String stringQuery) {
278 		return new JLogQuery(this, stringQuery);
279 	}
280 
281 	@Override
282 	public PrologQuery query(PrologTerm term) {
283 		return new JLogQuery(this, term);
284 	}
285 
286 	public PrologQuery query(PrologTerm[] terms) {
287 		return new JLogQuery(this, terms);
288 	}
289 
290 	public PrologQuery query(PrologTerm term, PrologTerm... terms) {
291 		return new JLogQuery(this, term, terms);
292 	}
293 
294 	public void operator(int priority, String specifier, String operator) {
295 		pOperatorEntry op = new pPredicateOperatorEntry(operator, getType(specifier), priority);
296 		engine.getOperatorRegistry().addOperator(op);
297 	}
298 
299 	public boolean currentPredicate(String functor, int arity) {
300 		PrologIndicator pi = new JLogIndicator(functor, arity);
301 		return currentPredicates().contains(pi);
302 	}
303 
304 	public boolean currentOperator(int priority, String specifier, String operator) {
305 		pOperatorEntry op = engine.getOperatorRegistry().getOperator(operator, true);
306 		op = op == null ? engine.getOperatorRegistry().getOperator(operator, false) : op;
307 		return op != null && op.getPriority() == priority && op.getType() == getType(specifier);
308 	}
309 
310 	public Set<PrologOperator> currentOperators() {
311 		HashSet<PrologOperator> operators = new HashSet<PrologOperator>();
312 		Enumeration<?> e = engine.getOperatorRegistry().enumOperators();
313 		while (e.hasMoreElements()) {
314 			Object object = e.nextElement();
315 			if (object instanceof pOperatorEntry) {
316 				pOperatorEntry entry = (pOperatorEntry) object;
317 				String specifier = "";
318 				String operator = entry.getName();
319 				int priority = entry.getPriority();
320 				switch (entry.getType()) {
321 				case FX:
322 					specifier = "fx";
323 					break;
324 				case FY:
325 					specifier = "fy";
326 					break;
327 				case XFX:
328 					specifier = "xfx";
329 					break;
330 				case XFY:
331 					specifier = "xfy";
332 					break;
333 				case YFX:
334 					specifier = "yfx";
335 					break;
336 				case XF:
337 					specifier = "xf";
338 					break;
339 				default:
340 					specifier = "yf";
341 					break;
342 				}
343 				PrologOperator op = new JLogOperator(priority, specifier, operator);
344 				operators.add(op);
345 			}
346 		}
347 		return operators;
348 	}
349 
350 	private int getType(String specifier) {
351 		int type = -1;
352 		if (specifier.equals("fx")) {
353 			type = FX;
354 		} else if (specifier.equals("fy")) {
355 			type = FY;
356 		} else if (specifier.equals("xfx")) {
357 			type = XFX;
358 		} else if (specifier.equals("xfy")) {
359 			type = XFY;
360 		} else if (specifier.equals("yfx")) {
361 			type = YFX;
362 		} else if (specifier.equals("xf")) {
363 			type = XF;
364 		} else if (specifier.equals("yf")) {
365 			type = YF;
366 		}
367 		return type;
368 	}
369 
370 	public Iterator<PrologClause> iterator() {
371 		Collection<PrologClause> cls = new LinkedList<PrologClause>();
372 		Enumeration<?> enumeration = kb.enumDefinitions();
373 		while (enumeration.hasMoreElements()) {
374 			jRuleDefinitions object = (jRuleDefinitions) enumeration.nextElement();
375 			Enumeration<?> r = object.enumRules();
376 			while (r.hasMoreElements()) {
377 				Object object2 = r.nextElement();
378 				if (!(object2 instanceof jBuiltinRule)) {
379 					jRule jRule = (jRule) object2;
380 
381 					// rule head
382 					jPredicate ruleHead = jRule.getHead();
383 					PrologTerm head = toTerm(ruleHead, PrologTerm.class);
384 
385 					// rule body
386 					jPredicateTerms ruleBody = jRule.getBase();
387 					PrologTerm body = toTerm(ruleBody, PrologTerm.class);
388 
389 					// rule end
390 					if (!(body instanceof JLogTrue)) {
391 						cls.add(new JLogClause(provider, head, body, false, false, false));
392 					} else {
393 						cls.add(new JLogClause(provider, head, false, false, false));
394 					}
395 
396 				}
397 			}
398 		}
399 		return new PrologProgramIterator(cls);
400 	}
401 
402 	public int getProgramSize() {
403 		int programSize = 0;
404 		Enumeration<?> de = kb.enumDefinitions();
405 		while (de.hasMoreElements()) {
406 			jRuleDefinitions rules = (jRuleDefinitions) de.nextElement();
407 			Enumeration<?> re = rules.enumRules();
408 			while (re.hasMoreElements()) {
409 				Object rule = re.nextElement();
410 				if (!(rule instanceof jBuiltinRule)) {
411 					programSize++;
412 				}
413 			}
414 		}
415 		return programSize;
416 	}
417 
418 	@Override
419 	public PrologProgram getProgram() {
420 		return new JLogProgram(this);
421 	}
422 
423 	public Set<PrologIndicator> getPredicates() {
424 		Set<PrologIndicator> predicates = new HashSet<PrologIndicator>();
425 		Enumeration<?> e = kb.enumDefinitions();
426 		while (e.hasMoreElements()) {
427 			jRuleDefinitions definitions = (jRuleDefinitions) e.nextElement();
428 			Enumeration<?> rules = definitions.enumRules();
429 			while (rules.hasMoreElements()) {
430 				Object object2 = rules.nextElement();
431 				if (!(object2 instanceof jBuiltinRule)) {
432 					jRule jRule = (jRule) object2;
433 					jPredicate ruleHead = jRule.getHead();
434 					String functor = ruleHead.getName();
435 					int arity = ruleHead.getArity();
436 					JLogIndicator pi = new JLogIndicator(functor, arity);
437 					predicates.add(pi);
438 				}
439 			}
440 		}
441 		return predicates;
442 	}
443 
444 	public Set<PrologIndicator> getBuiltIns() {
445 		Set<PrologIndicator> builtins = new HashSet<PrologIndicator>();
446 		Enumeration<?> e = engine.getPredicateRegistry().enumPredicates();
447 		while (e.hasMoreElements()) {
448 			Object object = e.nextElement();
449 			if (object instanceof pGenericPredicateEntry) {
450 				pGenericPredicateEntry entry = (pGenericPredicateEntry) object;
451 				String functor = entry.getName();
452 				int arity = entry.getArity();
453 				JLogIndicator pi = new JLogIndicator(functor, arity);
454 				builtins.add(pi);
455 			}
456 		}
457 		return builtins;
458 	}
459 
460 	public String getLicense() {
461 		return Licenses.GPL_V2;
462 	}
463 
464 	public String getVersion() {
465 		String credits = jPrologServices.getRequiredCreditInfo();
466 		StringTokenizer tokenizer = new StringTokenizer(credits);
467 		/* String name = */tokenizer.nextToken();
468 		return tokenizer.nextToken();
469 	}
470 
471 	public String getVendor() {
472 		String credits = jPrologServices.getRequiredCreditInfo();
473 		StringTokenizer tokenizer = new StringTokenizer(credits);
474 		return tokenizer.nextToken();
475 	}
476 
477 	public String getName() {
478 		String credits = jPrologServices.getRequiredCreditInfo();
479 		StringTokenizer tokenizer = new StringTokenizer(credits);
480 		return tokenizer.nextToken();
481 	}
482 
483 	@Override
484 	public int hashCode() {
485 		final int prime = 31;
486 		int result = 1;
487 		result = prime * result + engine.hashCode();
488 		result = prime * result + kb.hashCode();
489 		result = prime * result + or.hashCode();
490 		result = prime * result + pr.hashCode();
491 		return result;
492 	}
493 
494 	@Override
495 	public boolean equals(Object obj) {
496 		if (this == obj)
497 			return true;
498 		if (obj == null)
499 			return false;
500 		if (getClass() != obj.getClass())
501 			return false;
502 		JLogEngine other = (JLogEngine) obj;
503 		if (!engine.equals(other.engine))
504 			return false;
505 		if (!kb.equals(other.kb))
506 			return false;
507 		if (!or.equals(other.or))
508 			return false;
509 		return pr.equals(other.pr);
510 	}
511 
512 	public void dispose() {
513 		engine.release();
514 		kb.clearRules();
515 	}
516 
517 	public final List<String> verify() {
518 		return Arrays.asList("OK");
519 	}
520 
521 }