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.PrologTermType.ATOM_TYPE;
25  import static io.github.prolobjectlink.prolog.PrologTermType.CLASS_TYPE;
26  import static io.github.prolobjectlink.prolog.PrologTermType.CUT_TYPE;
27  import static io.github.prolobjectlink.prolog.PrologTermType.DOUBLE_TYPE;
28  import static io.github.prolobjectlink.prolog.PrologTermType.FAIL_TYPE;
29  import static io.github.prolobjectlink.prolog.PrologTermType.FALSE_TYPE;
30  import static io.github.prolobjectlink.prolog.PrologTermType.FIELD_TYPE;
31  import static io.github.prolobjectlink.prolog.PrologTermType.FLOAT_TYPE;
32  import static io.github.prolobjectlink.prolog.PrologTermType.INTEGER_TYPE;
33  import static io.github.prolobjectlink.prolog.PrologTermType.LIST_TYPE;
34  import static io.github.prolobjectlink.prolog.PrologTermType.LONG_TYPE;
35  import static io.github.prolobjectlink.prolog.PrologTermType.MAP_ENTRY_TYPE;
36  import static io.github.prolobjectlink.prolog.PrologTermType.MAP_TYPE;
37  import static io.github.prolobjectlink.prolog.PrologTermType.MIXIN_TYPE;
38  import static io.github.prolobjectlink.prolog.PrologTermType.NIL_TYPE;
39  import static io.github.prolobjectlink.prolog.PrologTermType.OBJECT_TYPE;
40  import static io.github.prolobjectlink.prolog.PrologTermType.PARAMETER_TYPE;
41  import static io.github.prolobjectlink.prolog.PrologTermType.RESULT_TYPE;
42  import static io.github.prolobjectlink.prolog.PrologTermType.STRUCTURE_TYPE;
43  import static io.github.prolobjectlink.prolog.PrologTermType.TRUE_TYPE;
44  import static io.github.prolobjectlink.prolog.PrologTermType.VARIABLE_TYPE;
45  
46  import java.util.ArrayList;
47  import java.util.Enumeration;
48  import java.util.Iterator;
49  
50  import io.github.prolobjectlink.prolog.AbstractConverter;
51  import io.github.prolobjectlink.prolog.PrologAtom;
52  import io.github.prolobjectlink.prolog.PrologConverter;
53  import io.github.prolobjectlink.prolog.PrologDouble;
54  import io.github.prolobjectlink.prolog.PrologFloat;
55  import io.github.prolobjectlink.prolog.PrologInteger;
56  import io.github.prolobjectlink.prolog.PrologList;
57  import io.github.prolobjectlink.prolog.PrologLogger;
58  import io.github.prolobjectlink.prolog.PrologLong;
59  import io.github.prolobjectlink.prolog.PrologProvider;
60  import io.github.prolobjectlink.prolog.PrologStructure;
61  import io.github.prolobjectlink.prolog.PrologTerm;
62  import io.github.prolobjectlink.prolog.PrologVariable;
63  import io.github.prolobjectlink.prolog.UnknownTermError;
64  import ubc.cs.JLog.Foundation.jEquivalenceMapping;
65  import ubc.cs.JLog.Terms.jAtom;
66  import ubc.cs.JLog.Terms.jBinaryBuiltinPredicate;
67  import ubc.cs.JLog.Terms.jBuiltinPredicate;
68  import ubc.cs.JLog.Terms.jCompoundTerm;
69  import ubc.cs.JLog.Terms.jFail;
70  import ubc.cs.JLog.Terms.jInteger;
71  import ubc.cs.JLog.Terms.jList;
72  import ubc.cs.JLog.Terms.jListPair;
73  import ubc.cs.JLog.Terms.jNullList;
74  import ubc.cs.JLog.Terms.jObject;
75  import ubc.cs.JLog.Terms.jPredicate;
76  import ubc.cs.JLog.Terms.jPredicateTerms;
77  import ubc.cs.JLog.Terms.jReal;
78  import ubc.cs.JLog.Terms.jTerm;
79  import ubc.cs.JLog.Terms.jTrue;
80  import ubc.cs.JLog.Terms.jUnaryBuiltinPredicate;
81  import ubc.cs.JLog.Terms.jVariable;
82  
83  /**
84   * 
85   * @author Jose Zalacain
86   * @since 1.0
87   */
88  class JLogConverter extends AbstractConverter<jTerm> implements PrologConverter<jTerm> {
89  
90  	private final jPredicateTerms emptyBody = new jPredicateTerms();
91  	private final jEquivalenceMapping equivalence = new jEquivalenceMapping();
92  
93  	private jList adaptList(PrologTerm[] arguments) {
94  		jList pList = jNullList.NULL_LIST;
95  		for (int i = arguments.length - 1; i >= 0; --i) {
96  			pList = new jListPair(fromTerm(arguments[i]), pList);
97  		}
98  		return pList;
99  	}
100 
101 	private jCompoundTerm adaptCompound(PrologTerm[] arguments) {
102 		jCompoundTerm compound = new jCompoundTerm(arguments.length);
103 		for (PrologTerm iPrologTerm : arguments) {
104 			compound.addTerm(fromTerm(iPrologTerm));
105 		}
106 		return compound;
107 	}
108 
109 	public PrologTerm toTerm(jTerm prologTerm) {
110 		switch (prologTerm.type) {
111 		case jTerm.TYPE_NULLLIST:
112 			return new JLogEmpty(provider);
113 		case jTerm.TYPE_ATOM:
114 			String value = prologTerm.getName();
115 			if (value.equals(JLogNil.NIL_STR)) {
116 				return new JLogNil(provider);
117 			} else if (value.equals(JLogFalse.FALSE_STR)) {
118 				return new JLogFalse(provider);
119 			} else if (!value.matches(SIMPLE_ATOM_REGEX)) {
120 				return new JLogAtom(provider, "'" + value + "'");
121 			}
122 			return new JLogAtom(provider, value);
123 		case jTerm.TYPE_INTEGER:
124 			return new JLogInteger(provider, ((jInteger) prologTerm).getIntegerValue());
125 		case jTerm.TYPE_REAL:
126 			JLogTerm number = null;
127 			try {
128 				if (prologTerm instanceof jFloat) {
129 					number = new JLogFloat(provider, ((jFloat) prologTerm).getRealValue());
130 				} else {
131 					number = new JLogDouble(provider, ((jDouble) prologTerm).getRealValue());
132 				}
133 			} catch (ClassCastException e) {
134 				// the parsed number is a jReal number we need convert in double or float
135 				if (e.getMessage().contains(jFloat.class.getName())) {
136 					number = new JLogFloat(provider, ((jReal) prologTerm).getRealValue());
137 				} else if (e.getMessage().contains(jDouble.class.getName())) {
138 					number = new JLogDouble(provider, ((jReal) prologTerm).getRealValue());
139 				} else {
140 					getLogger().error(getClass(), PrologLogger.CLASS_CAST, e);
141 				}
142 			}
143 			return number;
144 		case jTerm.TYPE_VARIABLE:
145 			String name = ((jVariable) prologTerm).getName();
146 			PrologVariable variable = sharedVariables.get(name);
147 			if (variable == null) {
148 				variable = new JLogVariable(provider, name);
149 				sharedVariables.put(variable.getName(), variable);
150 			}
151 			return variable;
152 		case jTerm.TYPE_LIST:
153 			jTerm[] array = new jTerm[0];
154 			jList list = (jList) prologTerm;
155 			ArrayList<jTerm> arguments = new ArrayList<jTerm>();
156 			Iterator<jTerm> i = new JLogIterator(list);
157 			while (i.hasNext()) {
158 				arguments.add(i.next());
159 			}
160 			return new JLogList(provider, arguments.toArray(array));
161 		case jTerm.TYPE_OBJECT:
162 			return new JLogReference(provider, prologTerm);
163 		case jTerm.TYPE_TYPE:
164 			jUnaryBuiltinPredicate unary = (jUnaryBuiltinPredicate) prologTerm;
165 			return new JLogStructure(provider, unary.getName(), unary.getRHS());
166 		case jTerm.TYPE_COMPARE:
167 		case jTerm.TYPE_OPERATOR:
168 		case jTerm.TYPE_ARITHMETIC:
169 		case jTerm.TYPE_UNARYOPERATOR:
170 		case jTerm.TYPE_NUMERICCOMPARE:
171 		case jTerm.TYPE_UNARYARITHMETIC:
172 			jBinaryBuiltinPredicate binary = (jBinaryBuiltinPredicate) prologTerm;
173 			return new JLogStructure(provider, binary.getLHS(), binary.getName(), binary.getRHS());
174 		case jTerm.TYPE_BUILTINPREDICATE:
175 			jBuiltinPredicate builtIn = (jBuiltinPredicate) prologTerm;
176 			if (builtIn.equivalence(jTrue.TRUE, equivalence)) {
177 				return new JLogTrue(provider);
178 			} else if (builtIn.equivalence(jFail.FAIL, equivalence)) {
179 				return new JLogFail(provider);
180 			} else if (builtIn.equivalence(JLogCut.JCUT, equivalence)) {
181 				return new JLogCut(provider);
182 			} else if (builtIn.getArity() == 2) {
183 				jBinaryBuiltinPredicate b = (jBinaryBuiltinPredicate) prologTerm;
184 				return new JLogStructure(provider, b.getLHS(), b.getName(), b.getRHS());
185 			}
186 			throw new UnknownTermError(prologTerm);
187 		case jTerm.TYPE_PREDICATE:
188 			jPredicate predicate = (jPredicate) prologTerm;
189 			jCompoundTerm compound = predicate.getArguments();
190 			String functor = predicate.getName();
191 			return new JLogStructure(provider, functor, compound);
192 		case jTerm.TYPE_PREDICATETERMS:
193 			jPredicateTerms terms = (jPredicateTerms) prologTerm;
194 			Enumeration<?> k = terms.enumTerms();
195 			if (k.hasMoreElements()) {
196 				PrologTerm body = null;
197 				while (k.hasMoreElements()) {
198 					jTerm term = (jTerm) k.nextElement();
199 					if (body != null) {
200 						body = new JLogStructure(provider, ",", body, toTerm(term));
201 					} else {
202 						body = toTerm(term);
203 					}
204 				}
205 				return body;
206 			}
207 			return new JLogTrue(provider);
208 
209 		default:
210 			throw new UnknownTermError(prologTerm);
211 		}
212 	}
213 
214 	public jTerm fromTerm(PrologTerm term) {
215 		switch (term.getType()) {
216 		case NIL_TYPE:
217 			return new jAtom("nil");
218 		case CUT_TYPE:
219 			return new jAtom("!");
220 		case FAIL_TYPE:
221 			return jFail.FAIL;
222 		case TRUE_TYPE:
223 			return jTrue.TRUE;
224 		case FALSE_TYPE:
225 			return new jAtom("false");
226 		case ATOM_TYPE:
227 			String value = ((PrologAtom) term).getStringValue();
228 			return new jAtom(value);
229 		case FLOAT_TYPE:
230 			return new jFloat(((PrologFloat) term).getFloatValue());
231 		case INTEGER_TYPE:
232 			return new jInteger(((PrologInteger) term).getIntegerValue());
233 		case DOUBLE_TYPE:
234 			return new jDouble(((PrologDouble) term).getDoubleValue());
235 		case LONG_TYPE:
236 			return new jInteger(((PrologLong) term).getIntegerValue());
237 		case VARIABLE_TYPE:
238 			String name = ((PrologVariable) term).getName();
239 			jTerm variable = sharedPrologVariables.get(name);
240 			if (variable == null) {
241 				variable = new jVariable(name);
242 				sharedPrologVariables.put(name, variable);
243 			}
244 			return variable;
245 		case LIST_TYPE:
246 		case MAP_TYPE:
247 			PrologTerm[] arguments = ((PrologList) term).getArguments();
248 			return adaptList(arguments);
249 		case STRUCTURE_TYPE:
250 		case MAP_ENTRY_TYPE:
251 			String functor = term.getFunctor();
252 			arguments = ((PrologStructure) term).getArguments();
253 			return new jPredicate(functor, adaptCompound(arguments));
254 		case OBJECT_TYPE:
255 			return new jObject(term.getObject());
256 		case PARAMETER_TYPE:
257 		case RESULT_TYPE:
258 		case FIELD_TYPE:
259 			name = ((PrologVariable) term).getName();
260 			return new jVariable(name);
261 		case MIXIN_TYPE:
262 		case CLASS_TYPE:
263 			arguments = term.getArguments();
264 			functor = removeQuoted(term.getFunctor());
265 			return new jPredicate(functor, adaptCompound(arguments));
266 		default:
267 			throw new UnknownTermError(term);
268 		}
269 	}
270 
271 	public jTerm[] fromTermArray(PrologTerm[] terms) {
272 		jTerm[] prologTerms = new jTerm[terms.length];
273 		for (int i = 0; i < terms.length; i++) {
274 			prologTerms[i] = fromTerm(terms[i]);
275 		}
276 		return prologTerms;
277 	}
278 
279 	public jTerm fromTerm(PrologTerm head, PrologTerm[] body) {
280 		jTerm clauseHead = fromTerm(head);
281 		if (body != null && body.length > 0) {
282 			jTerm clauseBody = fromTerm(body[body.length - 1]);
283 			for (int i = body.length - 2; i >= 0; --i) {
284 				jCompoundTerm args = new jCompoundTerm(2);
285 				args.addTerm(fromTerm(body[i]));
286 				args.addTerm(clauseBody);
287 				clauseBody = new jPredicate(",", args);
288 			}
289 			jCompoundTerm args = new jCompoundTerm(2);
290 			args.addTerm(clauseHead);
291 			args.addTerm(clauseBody);
292 			return new jPredicate(":-", args);
293 		}
294 		return clauseHead;
295 	}
296 
297 	public PrologProvider createProvider() {
298 		return new JLog(this);
299 	}
300 
301 	@Override
302 	public int hashCode() {
303 		final int prime = 31;
304 		int result = super.hashCode();
305 		result = prime * result + emptyBody.hashCode();
306 		result = prime * result + equivalence.hashCode();
307 		return result;
308 	}
309 
310 	@Override
311 	public boolean equals(Object object) {
312 		if (this == object)
313 			return true;
314 		if (!super.equals(object))
315 			return false;
316 		if (getClass() != object.getClass())
317 			return false;
318 		JLogConverter other = (JLogConverter) object;
319 		if (!emptyBody.equals(other.emptyBody))
320 			return false;
321 		return equivalence.equals(other.equivalence);
322 	}
323 
324 	@Override
325 	public String toString() {
326 		return "JLogConverter";
327 	}
328 
329 }