View Javadoc

1   /*
2    * #%L
3    * prolobjectlink-jpi-jpl7
4    * %%
5    * Copyright (C) 2019 Prolobjectlink Project
6    * %%
7    * Redistribution and use in source and binary forms, with or without
8    * modification, are permitted provided that the following conditions are met:
9    * 
10   * 1. Redistributions of source code must retain the above copyright notice,
11   *    this list of conditions and the following disclaimer.
12   * 2. Redistributions in binary form must reproduce the above copyright notice,
13   *    this list of conditions and the following disclaimer in the documentation
14   *    and/or other materials provided with the distribution.
15   * 
16   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17   * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19   * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
20   * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22   * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23   * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24   * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26   * POSSIBILITY OF SUCH DAMAGE.
27   * #L%
28   */
29  package io.github.prolobjectlink.prolog.jpl7;
30  
31  import java.util.AbstractSet;
32  import java.util.Iterator;
33  import java.util.LinkedHashMap;
34  import java.util.LinkedList;
35  import java.util.List;
36  import java.util.Map;
37  import java.util.Set;
38  
39  import org.jpl7.Term;
40  
41  import io.github.prolobjectlink.prolog.ArrayIterator;
42  import io.github.prolobjectlink.prolog.PrologClauses;
43  import io.github.prolobjectlink.prolog.PrologError;
44  
45  /**
46   * 
47   * @author Jose Zalacain
48   * @since 1.0
49   */
50  final class JplProgram extends AbstractSet<List<Term>> {
51  
52  	//
53  	private final JplParser parser = new JplParser();
54  
55  	// program initializations goals
56  	private final List<Term> goals = new LinkedList<Term>();
57  
58  	// list of directives goals
59  	private final List<Term> directives = new LinkedList<Term>();
60  
61  	// program (data base) in read order
62  	private final LinkedHashMap<String, List<Term>> clauses = new LinkedHashMap<String, List<Term>>();
63  
64  	private String getKey(Term clause) {
65  		String key = clause.name();
66  		key += "/" + clause.arity();
67  		if (key.equals(":-/2")) {
68  			key = clause.arg(1).name();
69  			key += "/";
70  			key += clause.arg(1).arity();
71  		}
72  		return key;
73  	}
74  
75  	private String getKey(List<Term> cls) {
76  		String msg = "Empty clause list";
77  		if (!cls.isEmpty()) {
78  			Term t = cls.get(0);
79  			String key = t.name();
80  			key += "/" + t.arity();
81  			return key;
82  		}
83  		throw new PrologError(msg);
84  	}
85  
86  	public List<Term> get(String key) {
87  		return clauses.get(key);
88  	}
89  
90  	public void add(Term clause) {
91  		String key = getKey(clause);
92  		List<Term> family = get(key);
93  		if (family == null) {
94  			family = new LinkedList<Term>();
95  			family.add(clause);
96  			clauses.put(key, family);
97  		} else if (!family.contains(clause)) {
98  			family.add(clause);
99  		}
100 	}
101 
102 	@Override
103 	public boolean add(List<Term> cls) {
104 		String key = getKey(cls);
105 		List<Term> family = get(key);
106 		if (family != null) {
107 			family.addAll(cls);
108 		} else {
109 			clauses.put(key, cls);
110 		}
111 		return true;
112 	}
113 
114 	public void add(JplProgram program) {
115 		goals.addAll(program.getGoals());
116 		clauses.putAll(program.getClauses());
117 		directives.addAll(program.getDirectives());
118 	}
119 
120 	@Override
121 	public boolean remove(Object o) {
122 
123 		if (o instanceof Term) {
124 			Term c = (Term) o;
125 			String key = getKey(c);
126 			List<Term> family = get(key);
127 			if (family != null) {
128 				return family.remove(c);
129 			}
130 		}
131 
132 		else if (o instanceof PrologClauses) {
133 			PrologClauses cs = (PrologClauses) o;
134 			String key = cs.getIndicator();
135 			List<Term> oldFamily = clauses.remove(key);
136 			return oldFamily != null;
137 		}
138 
139 		return false;
140 	}
141 
142 	public boolean remove(Term o) {
143 
144 		if (o instanceof Term) {
145 			String key = getKey(o);
146 			List<Term> family = get(key);
147 			if (family != null) {
148 				return family.remove(o);
149 			}
150 		}
151 
152 		return false;
153 	}
154 
155 	public void push(Term clause) {
156 		String key = getKey(clause);
157 		List<Term> family = clauses.remove(key);
158 		List<Term> cs = new LinkedList<Term>();
159 		if (family != null && !family.contains(clause)) {
160 			cs.add(clause);
161 			for (Term term : family) {
162 				cs.add(term);
163 			}
164 		} else {
165 			cs.add(clause);
166 		}
167 		clauses.put(key, cs);
168 	}
169 
170 	public void removeAll(String key) {
171 		clauses.remove(key);
172 	}
173 
174 	public void removeAll(String functor, int arity) {
175 		removeAll(functor + "/" + arity);
176 	}
177 
178 	public List<Term> getDirectives() {
179 		return directives;
180 	}
181 
182 	public boolean addDirective(Term directive) {
183 		return directives.add(directive);
184 	}
185 
186 	public boolean removeDirective(Term directive) {
187 		return directives.remove(directive);
188 	}
189 
190 	public List<Term> getGoals() {
191 		return goals;
192 	}
193 
194 	public boolean addGoal(Term goal) {
195 		return goals.add(goal);
196 	}
197 
198 	public boolean removeGoal(Term goal) {
199 		return goals.remove(goal);
200 	}
201 
202 	public Set<String> getIndicators() {
203 		return clauses.keySet();
204 	}
205 
206 	public Map<String, List<Term>> getClauses() {
207 		return clauses;
208 	}
209 
210 	@Override
211 	public String toString() {
212 
213 		StringBuilder families = new StringBuilder();
214 
215 		if (!directives.isEmpty()) {
216 			Iterator<Term> i = directives.iterator();
217 			while (i.hasNext()) {
218 				families.append(":-");
219 				families.append(i.next());
220 				families.append('.');
221 				families.append(i.hasNext() ? "\n" : "\n\n");
222 			}
223 		}
224 
225 		if (!clauses.isEmpty()) {
226 			Iterator<List<Term>> i = iterator();
227 			while (i.hasNext()) {
228 				List<Term> l = i.next();
229 				Iterator<Term> j = l.iterator();
230 				while (j.hasNext()) {
231 					Term term = j.next();
232 					String key = term.name();
233 					key += "/" + term.arity();
234 					if (term.arity() == 2 && key.equals(":-/2")) {
235 						Term h = term.arg(1);
236 						Term b = term.arg(2);
237 						families.append(h);
238 						families.append(" :- ");
239 						families.append('\n');
240 						families.append('\t');
241 						Term[] array = parser.parseTerms(b);
242 						Iterator<Term> k = new ArrayIterator<Term>(array);
243 						while (k.hasNext()) {
244 							Term item = k.next();
245 							families.append(item);
246 							if (k.hasNext()) {
247 								families.append(',');
248 								families.append('\n');
249 								families.append('\t');
250 							}
251 						}
252 					} else {
253 						families.append(term);
254 					}
255 					families.append('.');
256 					families.append('\n');
257 				}
258 				if (i.hasNext()) {
259 					families.append('\n');
260 				}
261 			}
262 		}
263 
264 		return "" + families + "";
265 	}
266 
267 	@Override
268 	public Iterator<List<Term>> iterator() {
269 		return clauses.values().iterator();
270 	}
271 
272 	@Override
273 	public int size() {
274 		int size = 0;
275 		Iterator<List<Term>> i = iterator();
276 		while (i.hasNext()) {
277 			List<Term> l = i.next();
278 			Iterator<Term> j = l.iterator();
279 			while (j.hasNext()) {
280 				j.next();
281 				size++;
282 			}
283 		}
284 		return size;
285 	}
286 
287 	@Override
288 	public void clear() {
289 		goals.clear();
290 		clauses.clear();
291 		directives.clear();
292 	}
293 
294 	@Override
295 	public int hashCode() {
296 		final int prime = 31;
297 		int result = super.hashCode();
298 		result = prime * result + clauses.hashCode();
299 		result = prime * result + directives.hashCode();
300 		result = prime * result + goals.hashCode();
301 		return result;
302 	}
303 
304 	@Override
305 	public boolean equals(Object obj) {
306 		if (this == obj)
307 			return true;
308 		if (!super.equals(obj))
309 			return false;
310 		if (getClass() != obj.getClass())
311 			return false;
312 		JplProgram other = (JplProgram) obj;
313 		if (!clauses.equals(other.clauses)) {
314 			return false;
315 		}
316 		if (!directives.equals(other.directives)) {
317 			return false;
318 		}
319 		return goals.equals(other.goals);
320 	}
321 
322 }