View Javadoc

1   /*
2    * #%L
3    * prolobjectlink-jpi
4    * %%
5    * Copyright (C) 2019 Prolobjectlink Project
6    * %%
7    * Permission is hereby granted, free of charge, to any person obtaining a copy
8    * of this software and associated documentation files (the "Software"), to deal
9    * in the Software without restriction, including without limitation the rights
10   * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11   * copies of the Software, and to permit persons to whom the Software is
12   * furnished to do so, subject to the following conditions:
13   * 
14   * The above copyright notice and this permission notice shall be included in
15   * all copies or substantial portions of the Software.
16   * 
17   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23   * THE SOFTWARE.
24   * #L%
25   */
26  package io.github.prolobjectlink.prolog;
27  
28  import java.util.ArrayList;
29  import java.util.Iterator;
30  import java.util.List;
31  import java.util.NoSuchElementException;
32  
33  /**
34   * Partial implementation of {@link PrologClause} interface.
35   * 
36   * @author Jose Zalacain
37   * @since 1.0
38   */
39  public abstract class AbstractClause implements PrologClause {
40  
41  	private String see = "";
42  	private String since = "";
43  	private String author = "";
44  	private String version = "";
45  	private String description = "";
46  
47  	private boolean dynamic;
48  	private boolean multifile;
49  	private boolean discontiguous;
50  
51  	private final PrologTerm head;
52  	private final PrologTerm body;
53  
54  	protected final PrologProvider provider;
55  
56  	/**
57  	 * Create a new fact clause. A fatc clause is only represented by clause head
58  	 * and no have clause body. The body for this clause type is null. The other
59  	 * parameters are boolean clause properties. If a clause have any of this
60  	 * properties specify with true value.
61  	 * 
62  	 * @param provider      prolog provider
63  	 * @param head          clause head
64  	 * @param dynamic       true if clause is dynamic, false otherwise
65  	 * @param multifile     true if clause is multifile, false otherwise
66  	 * @param discontiguous true if clause is discontiguous, false otherwise
67  	 * @since 1.0
68  	 */
69  	protected AbstractClause(PrologProvider provider, PrologTerm head, boolean dynamic, boolean multifile,
70  			boolean discontiguous) {
71  		this(provider, head, null, dynamic, multifile, discontiguous);
72  	}
73  
74  	/**
75  	 * Create a new rule clause. A rule clause is represented by clause head and
76  	 * body. The other parameters are boolean clause properties. If a clause have
77  	 * any of this properties specify with true value.
78  	 * 
79  	 * @param provider      prolog provider
80  	 * @param head          clause head
81  	 * @param body          clause body
82  	 * @param dynamic       true if clause is dynamic, false otherwise
83  	 * @param multifile     true if clause is multifile, false otherwise
84  	 * @param discontiguous true if clause is discontiguous, false otherwise
85  	 * @since 1.0
86  	 */
87  	protected AbstractClause(PrologProvider provider, PrologTerm head, PrologTerm body, boolean dynamic,
88  			boolean multifile, boolean discontiguous) {
89  		this.head = head;
90  		this.body = body;
91  		this.provider = provider;
92  		this.dynamic = dynamic;
93  		this.multifile = multifile;
94  		this.discontiguous = discontiguous;
95  	}
96  
97  	public PrologTerm getTerm() {
98  		PrologTerm h = getHead();
99  		if (isRule()) {
100 			PrologTerm b = getBody();
101 			return provider.newStructure(":-", h, b);
102 		}
103 		return h;
104 	}
105 
106 	public final PrologTerm getHead() {
107 		return head;
108 	}
109 
110 	public final PrologTerm getBody() {
111 		return body;
112 	}
113 
114 	public final PrologTerm[] getBodyArray() {
115 		PrologTerm ptr = getBody();
116 		List<PrologTerm> terms = new ArrayList<PrologTerm>();
117 		while (ptr != null && ptr.isCompound() && ptr.hasIndicator(",", 2)) {
118 			terms.add(ptr.getArgument(0));
119 			ptr = ptr.getArgument(1);
120 		}
121 		terms.add(ptr);
122 		return terms.toArray(new PrologTerm[0]);
123 	}
124 
125 	public final Iterator<PrologTerm> getBodyIterator() {
126 		return new BodyIterator(getBodyArray());
127 	}
128 
129 	public final String getFunctor() {
130 		return head.getFunctor();
131 	}
132 
133 	public final int getArity() {
134 		return head.getArity();
135 	}
136 
137 	public PrologTerm[] getArguments() {
138 		return head.getArguments();
139 	}
140 
141 	public PrologTerm getArgument(int index) {
142 		return head.getArgument(index);
143 	}
144 
145 	public final boolean hasIndicator(String functor, int arity) {
146 		return getHead().hasIndicator(functor, arity);
147 	}
148 
149 	public final String getIndicator() {
150 		return head.getIndicator();
151 	}
152 
153 	public final boolean isDirective() {
154 		return head == null && body != null;
155 	}
156 
157 	public final boolean isFact() {
158 		return head != null && body == null;
159 	}
160 
161 	public final boolean isRule() {
162 		return head != null && body != null;
163 	}
164 
165 	public boolean isMethod() {
166 		return false;
167 	}
168 
169 	public boolean isFunction() {
170 		return false;
171 	}
172 
173 	public final boolean isClause() {
174 		return true;
175 	}
176 
177 	public final boolean isTerm() {
178 		return false;
179 	}
180 
181 	public final boolean unify(PrologClause clause) {
182 		return head.unify(clause.getHead()) && body.unify(clause.getBody());
183 	}
184 
185 	public final boolean isDynamic() {
186 		return dynamic;
187 	}
188 
189 	public final boolean isMultifile() {
190 		return multifile;
191 	}
192 
193 	public final boolean isDiscontiguous() {
194 		return discontiguous;
195 	}
196 
197 	public PrologIndicator getPrologIndicator() {
198 		return new DefaultPrologIndicator(getFunctor(), getArity());
199 	}
200 
201 	public final <T extends PrologClause> T cast() {
202 		return (T) this;
203 	}
204 
205 	public final String getSee() {
206 		return see;
207 	}
208 
209 	public final void setSee(String see) {
210 		this.see = see;
211 	}
212 
213 	public final String getSince() {
214 		return since;
215 	}
216 
217 	public final void setSince(String since) {
218 		this.since = since;
219 	}
220 
221 	public final String getAuthor() {
222 		return author;
223 	}
224 
225 	public final void setAuthor(String author) {
226 		this.author = author;
227 	}
228 
229 	public final String getVersion() {
230 		return version;
231 	}
232 
233 	public final void setVersion(String version) {
234 		this.version = version;
235 	}
236 
237 	public final String getDescription() {
238 		return description;
239 	}
240 
241 	public final void setDescription(String description) {
242 		this.description = description;
243 	}
244 
245 	public final boolean hasDescription() {
246 		return !getDescription().isEmpty();
247 	}
248 
249 	public final boolean hasVersion() {
250 		return !getVersion().isEmpty();
251 	}
252 
253 	public final boolean hasAuthor() {
254 		return !getAuthor().isEmpty();
255 	}
256 
257 	public final boolean hasSince() {
258 		return !getSince().isEmpty();
259 	}
260 
261 	public final boolean hasSee() {
262 		return !getSee().isEmpty();
263 	}
264 
265 	public final boolean hasDocumentation() {
266 		return hasDescription() || hasVersion() || hasAuthor() || hasSince() || hasSee();
267 	}
268 
269 	@Override
270 	public int hashCode() {
271 		final int prime = 31;
272 		int result = 1;
273 		result = prime * result + ((author == null) ? 0 : author.hashCode());
274 		result = prime * result + ((body == null) ? 0 : body.hashCode());
275 		result = prime * result + ((description == null) ? 0 : description.hashCode());
276 		result = prime * result + (discontiguous ? 1231 : 1237);
277 		result = prime * result + (dynamic ? 1231 : 1237);
278 		result = prime * result + ((head == null) ? 0 : head.hashCode());
279 		result = prime * result + (multifile ? 1231 : 1237);
280 		result = prime * result + ((see == null) ? 0 : see.hashCode());
281 		result = prime * result + ((since == null) ? 0 : since.hashCode());
282 		result = prime * result + ((version == null) ? 0 : version.hashCode());
283 		return result;
284 	}
285 
286 	@Override
287 	public boolean equals(Object obj) {
288 		if (this == obj)
289 			return true;
290 		if (obj == null)
291 			return false;
292 		if (getClass() != obj.getClass())
293 			return false;
294 		AbstractClause other = (AbstractClause) obj;
295 		if (author == null) {
296 			if (other.author != null)
297 				return false;
298 		} else if (!author.equals(other.author))
299 			return false;
300 		if (body == null) {
301 			if (other.body != null)
302 				return false;
303 		} else if (!body.equals(other.body))
304 			return false;
305 		if (description == null) {
306 			if (other.description != null)
307 				return false;
308 		} else if (!description.equals(other.description))
309 			return false;
310 		if (discontiguous != other.discontiguous)
311 			return false;
312 		if (dynamic != other.dynamic)
313 			return false;
314 		if (head == null) {
315 			if (other.head != null)
316 				return false;
317 		} else if (!head.equals(other.head))
318 			return false;
319 		if (multifile != other.multifile)
320 			return false;
321 		if (see == null) {
322 			if (other.see != null)
323 				return false;
324 		} else if (!see.equals(other.see))
325 			return false;
326 		if (since == null) {
327 			if (other.since != null)
328 				return false;
329 		} else if (!since.equals(other.since))
330 			return false;
331 		if (version == null) {
332 			if (other.version != null)
333 				return false;
334 		} else if (!version.equals(other.version))
335 			return false;
336 		return true;
337 	}
338 
339 	@Override
340 	public String toString() {
341 		StringBuilder b = new StringBuilder();
342 		if (hasDocumentation()) {
343 			b.append("/*");
344 			if (hasDescription()) {
345 				b.append(getDescription());
346 				b.append("\n");
347 			}
348 			if (hasVersion()) {
349 				b.append(getVersion());
350 				b.append("\n");
351 			}
352 			if (hasAuthor()) {
353 				b.append(getAuthor());
354 				b.append("\n");
355 			}
356 			if (hasSince()) {
357 				b.append(getSince());
358 				b.append("\n");
359 			}
360 			if (hasSee()) {
361 				b.append(getSee());
362 				b.append("\n");
363 			}
364 			b.append("*/");
365 		}
366 		b.append(getHead());
367 		if (isRule()) {
368 			b.append(":-\n\t");
369 			Iterator<PrologTerm> i = getBodyIterator();
370 			while (i.hasNext()) {
371 				b.append(i.next());
372 				if (i.hasNext()) {
373 					b.append(",\n\t");
374 				}
375 			}
376 		}
377 		b.append('.');
378 		return "" + b + "";
379 	}
380 
381 	private class BodyIterator extends AbstractIterator<PrologTerm> implements Iterator<PrologTerm> {
382 
383 		private int nextIndex;
384 
385 		private final PrologTerm[] elements;
386 
387 		protected BodyIterator(PrologTerm[] elements) {
388 			this.elements = elements;
389 		}
390 
391 		public boolean hasNext() {
392 			return nextIndex < elements.length;
393 		}
394 
395 		public PrologTerm next() {
396 			if (!hasNext()) {
397 				throw new NoSuchElementException();
398 			}
399 			return elements[nextIndex++];
400 		}
401 
402 	}
403 
404 }