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.AbstractConverter.SIMPLE_ATOM_REGEX;
25  import static io.github.prolobjectlink.prolog.jlog.JLog.FUNCTORS;
26  
27  import java.io.PrintWriter;
28  import java.io.StringWriter;
29  import java.util.Enumeration;
30  import java.util.Map.Entry;
31  
32  import io.github.prolobjectlink.prolog.PrologProvider;
33  import io.github.prolobjectlink.prolog.PrologTerm;
34  import io.github.prolobjectlink.prolog.StructureExpectedError;
35  import ubc.cs.JLog.Foundation.jKnowledgeBase;
36  import ubc.cs.JLog.Foundation.jPrologServices;
37  import ubc.cs.JLog.Foundation.jRule;
38  import ubc.cs.JLog.Foundation.jRuleDefinitions;
39  import ubc.cs.JLog.Parser.pOperatorRegistry;
40  import ubc.cs.JLog.Parser.pParseStream;
41  import ubc.cs.JLog.Parser.pPredicateRegistry;
42  import ubc.cs.JLog.Terms.jAtom;
43  import ubc.cs.JLog.Terms.jBuiltinRule;
44  import ubc.cs.JLog.Terms.jCompoundTerm;
45  import ubc.cs.JLog.Terms.jCons;
46  import ubc.cs.JLog.Terms.jIf;
47  import ubc.cs.JLog.Terms.jPredicate;
48  import ubc.cs.JLog.Terms.jPredicateTerms;
49  import ubc.cs.JLog.Terms.jTerm;
50  import ubc.cs.JLog.Terms.jVariable;
51  
52  /**
53   * Util class for {@link JLogTerm}
54   * 
55   * @author Jose Zalacain
56   * @since 1.0
57   *
58   */
59  final class JLogUtil {
60  
61  	private JLogUtil() {
62  	}
63  
64  	static final PrologTerm toTerm(PrologProvider provider, Object object) {
65  
66  		// null pointer
67  		if (object == null) {
68  			return new JLogNil(provider);
69  		}
70  
71  		// string data type
72  		else if (object instanceof String) {
73  			String string = (String) object;
74  			int index = string.indexOf('(');
75  			if (index > -1) {
76  				String functor = string.substring(0, index);
77  				String arguments = string.substring(index);
78  				if (!functor.matches(SIMPLE_ATOM_REGEX)) {
79  					StringBuilder buffer = new StringBuilder();
80  					buffer.append('\'');
81  					buffer.append(functor);
82  					buffer.append('\'');
83  					String quoted = "" + buffer + "";
84  					buffer.append(arguments);
85  					string = "" + buffer + "";
86  					FUNCTORS.put(functor, quoted);
87  
88  					// jlog need treatment for complex functors
89  					for (Entry<String, String> entry : FUNCTORS.entrySet()) {
90  
91  						// retrieve cached functors
92  						String key = entry.getKey();
93  						String value = entry.getValue();
94  
95  						// first and unique term pattern
96  						String firstRegex = "(" + key + "";
97  						if (string.contains(firstRegex)) {
98  							string = string.replaceAll(key, value);
99  						}
100 
101 						// non-first term pattern
102 						String nonFirstRegex = "," + key + "";
103 						if (string.contains(nonFirstRegex)) {
104 							string = string.replaceAll(key, value);
105 						}
106 
107 					}
108 				}
109 			}
110 
111 			return provider.parseTerm(string);
112 		}
113 
114 		// primitives and wrappers data types
115 		else if (object.getClass() == boolean.class || object instanceof Boolean) {
116 			return (Boolean) object ? new JLogTrue(provider) : new JLogFalse(provider);
117 		} else if (object.getClass() == int.class || object instanceof Integer) {
118 			return new JLogInteger(provider, (Integer) object);
119 		} else if (object.getClass() == float.class || object instanceof Float) {
120 			return new JLogFloat(provider, (Float) object);
121 		} else if (object.getClass() == long.class || object instanceof Long) {
122 			return new JLogLong(provider, (Long) object);
123 		} else if (object.getClass() == double.class || object instanceof Double) {
124 			return new JLogDouble(provider, (Double) object);
125 		}
126 
127 		//
128 		else if (object instanceof Object[]) {
129 			Object[] objects = (Object[]) object;
130 			PrologTerm[] terms = new PrologTerm[objects.length];
131 			for (int i = 0; i < objects.length; i++) {
132 				terms[i] = toTerm(provider, objects[i]);
133 			}
134 			return new JLogList(provider, terms);
135 		} else if (object instanceof jTerm) {
136 			return toTerm(provider, (jTerm) object);
137 		}
138 		return null;
139 	}
140 
141 	static final jRule toRule(String str, jPrologServices engine) {
142 		jPredicateTerms emptyBody = new jPredicateTerms();
143 		jKnowledgeBase ikb = engine.getKnowledgeBase();
144 		pOperatorRegistry ior = engine.getOperatorRegistry();
145 		pPredicateRegistry ipr = engine.getPredicateRegistry();
146 		String clause = str.charAt(str.length() - 1) == '.' ? str : str + '.';
147 		jTerm term = new pParseStream(clause, ikb, ipr, ior).parseTerm();
148 		if (term.type == jTerm.TYPE_PREDICATE) { // fact
149 			jPredicate predicate = (jPredicate) term;
150 			return new jRule(predicate, emptyBody);
151 		} else if (term.type == jTerm.TYPE_ATOM) {
152 			jAtom atom = (jAtom) term;
153 			jPredicate predicate = new jPredicate(atom);
154 			return new jRule(predicate, emptyBody);
155 		} else if (term.type == jTerm.TYPE_IF) { // rule
156 			jIf rule = (jIf) term;
157 			jPredicate h = (jPredicate) rule.getLHS();
158 			jTerm ruleBody = rule.getRHS();
159 			switch (ruleBody.type) {
160 
161 			// only and just only predicate
162 			case jTerm.TYPE_PREDICATE:
163 				jPredicate predicateBody = (jPredicate) ruleBody;
164 				jPredicateTerms b = new jPredicateTerms();
165 				b.addTerm(predicateBody);
166 				return new jRule(h, b);
167 
168 			//
169 			case jTerm.TYPE_CONS:
170 				b = new jPredicateTerms();
171 				while (ruleBody instanceof jCons) {
172 					b.addTerm(((jCons) ruleBody).getLHS());
173 					ruleBody = ((jCons) ruleBody).getRHS().getTerm();
174 				}
175 				b.addTerm(ruleBody);
176 				return new jRule(h, b);
177 
178 			case jTerm.TYPE_ATOM:
179 				jPredicateTerms atom = new jPredicateTerms();
180 				atom.addTerm(ruleBody);
181 				return new jRule(h, atom);
182 
183 			// cut type
184 			case jTerm.TYPE_BUILTINPREDICATE:
185 				jPredicateTerms builtin = new jPredicateTerms();
186 				builtin.addTerm(ruleBody);
187 				return new jRule(h, builtin);
188 
189 			//
190 			default:
191 				throw new StructureExpectedError(term);
192 			}
193 
194 		}
195 
196 		// no rule
197 		throw new StructureExpectedError(term);
198 
199 	}
200 
201 	static final jRule toRule(PrologProvider provider, PrologTerm head, PrologTerm... body) {
202 		jTerm termHead = provider.fromTerm(head, jTerm.class);
203 		if (termHead.type == jTerm.TYPE_PREDICATE || termHead.type == jTerm.TYPE_ATOM) {
204 			jPredicate predicateHead = null;
205 			if (termHead.type == jTerm.TYPE_PREDICATE) {
206 				predicateHead = (jPredicate) termHead;
207 			} else if (termHead.type == jTerm.TYPE_ATOM) {
208 				jAtom atomHead = (jAtom) termHead;
209 				predicateHead = new jPredicate(atomHead);
210 			}
211 			jPredicateTerms predicateBody = new jPredicateTerms();
212 			for (PrologTerm iPrologTerm : body) {
213 				predicateBody.addTerm(provider.fromTerm(iPrologTerm, jTerm.class));
214 			}
215 			return new jRule(predicateHead, predicateBody);
216 		}
217 		throw new StructureExpectedError(head);
218 	}
219 
220 	static final String toString(jPrologServices engine) {
221 		jKnowledgeBase kb = engine.getKnowledgeBase();
222 		StringWriter stringWriter = new StringWriter();
223 		PrintWriter writer = new PrintWriter(stringWriter);
224 		Enumeration<?> enumeration = kb.enumDefinitions();
225 		while (enumeration.hasMoreElements()) {
226 			jRuleDefinitions object = (jRuleDefinitions) enumeration.nextElement();
227 			Enumeration<?> r = object.enumRules();
228 			while (r.hasMoreElements()) {
229 				Object object2 = r.nextElement();
230 				if (!(object2 instanceof jBuiltinRule)) {
231 					jRule jRule = (jRule) object2;
232 
233 					// rule head
234 					jPredicate ruleHead = jRule.getHead();
235 					jCompoundTerm args = ruleHead.getArguments();
236 					String functor = ruleHead.getName();
237 					String ok = toString(functor, args);
238 					writer.print(ok);
239 
240 					// rule body
241 					jPredicateTerms ruleBody = jRule.getBase();
242 					Enumeration<?> k = ruleBody.enumTerms();
243 					if (k.hasMoreElements()) {
244 						writer.print(":-");
245 						while (k.hasMoreElements()) {
246 							jTerm term = (jTerm) k.nextElement();
247 							if (term instanceof jPredicate) {
248 								jPredicate p = (jPredicate) term;
249 								args = p.getArguments();
250 								functor = p.getName();
251 								ok = toString(functor, args);
252 								writer.print(ok);
253 							} else {
254 								writer.print(term);
255 							}
256 							if (k.hasMoreElements()) {
257 								writer.print(',');
258 							}
259 						}
260 					}
261 
262 					// rule end
263 					writer.println('.');
264 				}
265 			}
266 		}
267 		writer.flush();
268 		writer.close();
269 
270 		return "" + stringWriter + "";
271 	}
272 
273 	private static final String toString(String functor, jCompoundTerm args) {
274 		StringBuilder buffer = new StringBuilder();
275 		if (!functor.startsWith("'") && !functor.endsWith("'") && !functor.matches(SIMPLE_ATOM_REGEX)) {
276 			buffer.append('\'');
277 			buffer.append(functor);
278 			buffer.append('\'');
279 			String quoted = "" + buffer + "";
280 			FUNCTORS.put(functor, quoted);
281 		} else {
282 			buffer.append(functor);
283 		}
284 		Enumeration<?> e = args.enumTerms();
285 		if (e.hasMoreElements()) {
286 			buffer.append('(');
287 			while (e.hasMoreElements()) {
288 				jTerm jTerm = (jTerm) e.nextElement();
289 				if (jTerm instanceof jVariable) {
290 					jVariable jVar = (jVariable) jTerm;
291 					buffer.append(jVar.getName());
292 				} else if (jTerm instanceof jPredicate) {
293 					jPredicate p = (jPredicate) jTerm;
294 					String arg = toString(p.getName(), p.getArguments());
295 					buffer.append(arg);
296 				} else {
297 					buffer.append(jTerm);
298 				}
299 				if (e.hasMoreElements())
300 					buffer.append(',');
301 			}
302 			buffer.append(')');
303 		}
304 		return "" + buffer + "";
305 	}
306 
307 	static final String removeQuotesIfNeed(String functor) {
308 		if (functor.startsWith("'") && functor.endsWith("'")) {
309 			return functor.substring(1, functor.length() - 1);
310 		}
311 		return functor;
312 	}
313 
314 	static final String rectify(String str) {
315 		for (Entry<String, String> entry : FUNCTORS.entrySet()) {
316 
317 			// retrieve cached functors
318 			String key = entry.getKey();
319 			String value = entry.getValue();
320 
321 			// first and unique term pattern
322 			String firstRegex = "(" + key + "";
323 			if (str.contains(firstRegex)) {
324 				str = str.replaceAll(key, value);
325 			}
326 
327 			// non-first term pattern
328 			String nonFirstRegex = "," + key + "";
329 			if (str.contains(nonFirstRegex)) {
330 				str = str.replaceAll(key, value);
331 			}
332 
333 		}
334 		return str;
335 	}
336 
337 	private static final jPredicate retrieve(jPredicate predicate) {
338 		int arity = predicate.getArity();
339 		String functor = predicate.getName();
340 		if (functor.startsWith("'") && functor.endsWith("'")) {
341 			String nFunctor = functor.substring(1, functor.length() - 1);
342 			jCompoundTerm args = predicate.getArguments();
343 			jCompoundTerm nArgs = new jCompoundTerm(arity);
344 			for (int i = 0; i < args.size(); i++) {
345 				jTerm term = args.elementAt(i);
346 				if (term instanceof jPredicate) {
347 					jPredicate p = (jPredicate) term;
348 					nArgs.addTerm(retrieve(p));
349 				}
350 			}
351 			predicate = new jPredicate(nFunctor, nArgs);
352 		}
353 		return predicate;
354 	}
355 
356 }