View Javadoc

1   /*
2    * #%L
3    * prolobjectlink-jpi-jpl
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 Lesser General Public License as
9    * published by the Free Software Foundation, either version 2.1 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 Lesser Public License for more details.
16   * 
17   * You should have received a copy of the GNU General Lesser Public
18   * License along with this program.  If not, see
19   * <http://www.gnu.org/licenses/lgpl-2.1.html>.
20   * #L%
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   * @author Jose Zalacain
40   * @since 1.0
41   */
42  final class JplProgram extends AbstractSet<List<Term>> {
43  
44  	//
45  	private final JplParser parser = new JplParser();
46  
47  	// program initializations goals
48  	private final List<Term> goals = new LinkedList<Term>();
49  
50  	// list of directives goals
51  	private final List<Term> directives = new LinkedList<Term>();
52  
53  	// program (data base) in read order
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 }