1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 package io.github.prolobjectlink.prolog.jpl;
23
24 import java.util.AbstractSet;
25 import java.util.Iterator;
26 import java.util.LinkedHashMap;
27 import java.util.LinkedList;
28 import java.util.List;
29 import java.util.Map;
30 import java.util.Set;
31
32 import io.github.prolobjectlink.prolog.ArrayIterator;
33 import io.github.prolobjectlink.prolog.PrologClauses;
34 import io.github.prolobjectlink.prolog.PrologError;
35 import jpl.Term;
36
37
38
39
40
41
42 final class JplProgram extends AbstractSet<List<Term>> {
43
44
45 private final JplParser parser = new JplParser();
46
47
48 private final List<Term> goals = new LinkedList<Term>();
49
50
51 private final List<Term> directives = new LinkedList<Term>();
52
53
54 private final LinkedHashMap<String, List<Term>> clauses = new LinkedHashMap<String, List<Term>>();
55
56 private String getKey(Term clause) {
57 String key = clause.name();
58 key += "/" + clause.arity();
59 if (key.equals(":-/2")) {
60 key = clause.arg(1).name();
61 key += "/";
62 key += clause.arg(1).arity();
63 }
64 return key;
65 }
66
67 private String getKey(List<Term> cls) {
68 String msg = "Empty clause list";
69 if (!cls.isEmpty()) {
70 Term t = cls.get(0);
71 String key = t.name();
72 key += "/" + t.arity();
73 return key;
74 }
75 throw new PrologError(msg);
76 }
77
78 public List<Term> get(String key) {
79 return clauses.get(key);
80 }
81
82 public void add(Term clause) {
83 String key = getKey(clause);
84 List<Term> family = get(key);
85 if (family == null) {
86 family = new LinkedList<Term>();
87 family.add(clause);
88 clauses.put(key, family);
89 } else if (!family.contains(clause)) {
90 family.add(clause);
91 }
92 }
93
94 @Override
95 public boolean add(List<Term> cls) {
96 String key = getKey(cls);
97 List<Term> family = get(key);
98 if (family != null) {
99 family.addAll(cls);
100 } else {
101 clauses.put(key, cls);
102 }
103 return true;
104 }
105
106 public void add(JplProgram program) {
107 goals.addAll(program.getGoals());
108 clauses.putAll(program.getClauses());
109 directives.addAll(program.getDirectives());
110 }
111
112 @Override
113 public boolean remove(Object o) {
114
115 if (o instanceof Term) {
116 Term c = (Term) o;
117 String key = getKey(c);
118 List<Term> family = get(key);
119 if (family != null) {
120 return family.remove(c);
121 }
122 }
123
124 else if (o instanceof PrologClauses) {
125 PrologClauses cs = (PrologClauses) o;
126 String key = cs.getIndicator();
127 List<Term> oldFamily = clauses.remove(key);
128 return oldFamily != null;
129 }
130
131 return false;
132 }
133
134 public boolean remove(Term o) {
135
136 if (o instanceof Term) {
137 String key = getKey(o);
138 List<Term> family = get(key);
139 if (family != null) {
140 return family.remove(o);
141 }
142 }
143
144 return false;
145 }
146
147 public void push(Term clause) {
148 String key = getKey(clause);
149 List<Term> family = clauses.remove(key);
150 List<Term> cs = new LinkedList<Term>();
151 if (family != null && !family.contains(clause)) {
152 cs.add(clause);
153 for (Term term : family) {
154 cs.add(term);
155 }
156 } else {
157 cs.add(clause);
158 }
159 clauses.put(key, cs);
160 }
161
162 public void removeAll(String key) {
163 clauses.remove(key);
164 }
165
166 public void removeAll(String functor, int arity) {
167 removeAll(functor + "/" + arity);
168 }
169
170 public List<Term> getDirectives() {
171 return directives;
172 }
173
174 public boolean addDirective(Term directive) {
175 return directives.add(directive);
176 }
177
178 public boolean removeDirective(Term directive) {
179 return directives.remove(directive);
180 }
181
182 public List<Term> getGoals() {
183 return goals;
184 }
185
186 public boolean addGoal(Term goal) {
187 return goals.add(goal);
188 }
189
190 public boolean removeGoal(Term goal) {
191 return goals.remove(goal);
192 }
193
194 public Set<String> getIndicators() {
195 return clauses.keySet();
196 }
197
198 public Map<String, List<Term>> getClauses() {
199 return clauses;
200 }
201
202 @Override
203 public String toString() {
204
205 StringBuilder families = new StringBuilder();
206
207 if (!directives.isEmpty()) {
208 Iterator<Term> i = directives.iterator();
209 while (i.hasNext()) {
210 families.append(":-");
211 families.append(i.next());
212 families.append('.');
213 families.append(i.hasNext() ? "\n" : "\n\n");
214 }
215 }
216
217 if (!clauses.isEmpty()) {
218 Iterator<List<Term>> i = iterator();
219 while (i.hasNext()) {
220 List<Term> l = i.next();
221 Iterator<Term> j = l.iterator();
222 while (j.hasNext()) {
223 Term term = j.next();
224 String key = term.name();
225 key += "/" + term.arity();
226 if (term.arity() == 2 && key.equals(":-/2")) {
227 Term h = term.arg(1);
228 Term b = term.arg(2);
229 families.append(h);
230 families.append(" :- ");
231 families.append('\n');
232 families.append('\t');
233 Term[] array = parser.parseTerms(b);
234 Iterator<Term> k = new ArrayIterator<Term>(array);
235 while (k.hasNext()) {
236 Term item = k.next();
237 families.append(item);
238 if (k.hasNext()) {
239 families.append(',');
240 families.append('\n');
241 families.append('\t');
242 }
243 }
244 } else {
245 families.append(term);
246 }
247 families.append('.');
248 families.append('\n');
249 }
250 if (i.hasNext()) {
251 families.append('\n');
252 }
253 }
254 }
255
256 return "" + families + "";
257 }
258
259 @Override
260 public Iterator<List<Term>> iterator() {
261 return clauses.values().iterator();
262 }
263
264 @Override
265 public int size() {
266 int size = 0;
267 Iterator<List<Term>> i = iterator();
268 while (i.hasNext()) {
269 List<Term> l = i.next();
270 Iterator<Term> j = l.iterator();
271 while (j.hasNext()) {
272 j.next();
273 size++;
274 }
275 }
276 return size;
277 }
278
279 @Override
280 public void clear() {
281 goals.clear();
282 clauses.clear();
283 directives.clear();
284 }
285
286 @Override
287 public int hashCode() {
288 final int prime = 31;
289 int result = super.hashCode();
290 result = prime * result + clauses.hashCode();
291 result = prime * result + directives.hashCode();
292 result = prime * result + goals.hashCode();
293 return result;
294 }
295
296 @Override
297 public boolean equals(Object obj) {
298 if (this == obj)
299 return true;
300 if (!super.equals(obj))
301 return false;
302 if (getClass() != obj.getClass())
303 return false;
304 JplProgram other = (JplProgram) obj;
305 if (!clauses.equals(other.clauses)) {
306 return false;
307 }
308 if (!directives.equals(other.directives)) {
309 return false;
310 }
311 return goals.equals(other.goals);
312 }
313
314 }