View Javadoc

1   /*
2    * #%L
3    * prolobjectlink-jpi-jtrolog
4    * %%
5    * Copyright (C) 2012 - 2018 WorkLogic 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 jTrolog.engine;
23  
24  import jTrolog.errors.PrologException;
25  import jTrolog.parser.Parser;
26  import jTrolog.lib.Library;
27  import jTrolog.lib.BuiltIn;
28  import jTrolog.terms.Struct;
29  import jTrolog.terms.Term;
30  import jTrolog.terms.Clause;
31  
32  import java.io.Serializable;
33  import java.util.*;
34  import java.lang.reflect.InvocationTargetException;
35  
36  /**
37   * <p>
38   * This class defines the Library and Theory Manager who manages the libraries
39   * and clauses/theory often referred to as the Prolog database. The theory (as a
40   * set of clauses) are stored in the ClauseDatabase which in essence is a
41   * HashMap grouped by functor/arity.
42   * </p>
43   * <p>
44   * The LibraryAndTheoryManager functions logically, as prescribed by ISO
45   * Standard 7.5.4 section. The effects of assertions and retractions shall not
46   * be undone if the program subsequently backtracks over the assert or retract
47   * call, as prescribed by ISO Standard 7.7.9 section.
48   * </p>
49   * <p>
50   * To use the LibraryAndTheoryManager one should primarily use the methods
51   * assertA, assertZ, consult, retract, abolish and find.
52   * </p>
53   * rewritten by:
54   * 
55   * @author ivar.orstavik@hist.no
56   */
57  @SuppressWarnings({ "rawtypes", "unchecked","serial" })
58  class LibraryAndTheoryManager implements Serializable {
59  
60  	private ClauseDatabase dynamicDBase;
61  	private ClauseDatabase allLibraryRules;
62  
63  	private LinkedHashMap librariesToRules;
64  
65  	private Prolog engine;
66  	String lastConsultedTheory;
67  
68  	LibraryAndTheoryManager(Prolog vm) {
69  		dynamicDBase = new ClauseDatabase();
70  		librariesToRules = new LinkedHashMap();
71  		allLibraryRules = new ClauseDatabase();
72  		lastConsultedTheory = "";
73  		engine = vm;
74  	}
75  
76  	/**
77  	 * inserting of a clause at the head of the dbase
78  	 */
79  	void assertA(Clause clause, String index) throws PrologException {
80  		dynamicDBase.addFirst(index, clause);
81  	}
82  
83  	/**
84  	 * inserting of a clause at the end of the dbase
85  	 */
86  	void assertZ(Clause clause, String index) throws PrologException {
87  		dynamicDBase.addLast(index, clause);
88  	}
89  
90  	/**
91  	 * removing from dbase the first clause with head unifying with clause (m if
92  	 * a free substitution index and t is the first free timestamp)
93  	 */
94  	Struct retract(Struct clause, String index) throws PrologException {
95  		LinkedList family = (LinkedList) dynamicDBase.get(index);
96  		if (family == null)
97  			return null;
98  		for (Iterator it = family.iterator(); it.hasNext();) {
99  			Clause d = (Clause) it.next();
100 			if (Prolog.match(clause, d.original)) {
101 				it.remove();
102 				return d.original;
103 			}
104 		}
105 		return null;
106 	}
107 
108 	/**
109 	 * removes all clauses matching the given signature from the dynamic dbase
110 	 */
111 	List abolish(String index) throws PrologException {
112 		return dynamicDBase.abolish(index);
113 	}
114 
115 	/**
116 	 * registers a predicate indicator as known
117 	 */
118 	public void setDynamic(String index) {
119 		LinkedList family = (LinkedList) dynamicDBase.get(index);
120 		if (family != null)
121 			return;
122 		dynamicDBase.addFirst(index, Term.emptyList);
123 		family = (LinkedList) dynamicDBase.get(index);
124 		for (Iterator it = family.iterator(); it.hasNext();) {
125 			it.next();
126 			it.remove();
127 		}
128 	}
129 
130 	/**
131 	 * Returns a family of clauses with functor and arity equals to the functor
132 	 * and arity of the term passed as a parameter
133 	 */
134 	List find(String predIndicator) throws PrologException {
135 		List dynamics = dynamicDBase.getPredicatesIterator(predIndicator);
136 		return dynamics != null ? dynamics : allLibraryRules.getPredicatesIterator(predIndicator);
137 	}
138 
139 	/**
140 	 * Consults a theory.
141 	 * 
142 	 * @param theory
143 	 *            theory to add
144 	 * @throws PrologException
145 	 */
146 	void consult(String theory) throws PrologException {
147 		lastConsultedTheory = theory;
148 		// iterate all clauses in theory and assert them
149 		for (Iterator it = new Parser(theory, engine).iterator(); it.hasNext();) {
150 			Struct d = (Struct) it.next();
151 			if (runDirective(d))
152 				continue;
153 			// d = BuiltIn.convertTermToClause(d);
154 			Clause cl = BuiltIn.convertTermToClause(d);
155 			assertZ(cl, cl.head.predicateIndicator);
156 		}
157 	}
158 
159 	/**
160 	 * Clears the clause dbase.
161 	 */
162 	void clear() {
163 		dynamicDBase.clear();
164 	}
165 
166 	private boolean runDirective(Struct c) {
167 		if (c.predicateIndicator != Parser.singleClauseSignature)
168 			return false;
169 		Term dir = c.getArg(0);
170 		if (!(dir instanceof Struct))
171 			return false;
172 		try {
173 			try {
174 				PrimitiveInfo directive = engine.getPrimitive((Struct) dir);
175 				if (directive == null)
176 					engine.warn("The directive " + ((Struct) dir).predicateIndicator + " is unknown.");
177 				else {
178 					Object[] args = new Object[((Struct) dir).arity + 1];
179 					args[0] = new BindingsTable();
180 					for (int i = 0; i < ((Struct) dir).arity; i++)
181 						args[i + 1] = ((Struct) dir).getArg(i);
182 					Prolog.evalPrimitive(directive, args);
183 				}
184 			} catch (InvocationTargetException e) {
185 				Throwable cause = e;
186 				while (cause instanceof InvocationTargetException)
187 					cause = cause.getCause();
188 				throw cause;
189 			}
190 		} catch (Throwable cause) {
191 			engine.warn("An exception has been thrown during the execution of the " + ((Struct) dir).predicateIndicator + " directive.\n" + cause.getMessage());
192 		}
193 		return true;
194 	}
195 
196 	/**
197 	 * Gets current theory
198 	 * 
199 	 * @param onlyDynamic
200 	 *            if true, fetches only dynamic clauses
201 	 */
202 	public String getTheory(boolean onlyDynamic) {
203 		if (onlyDynamic)
204 			return dynamicDBase.toString();
205 		return dynamicDBase.toString() + "\n\n" + allLibraryRules.toString();
206 	}
207 
208 	/**
209 	 * Gets last consulted theory
210 	 * 
211 	 * @return last theory
212 	 */
213 	String getLastConsultedTheory() {
214 		return lastConsultedTheory;
215 	}
216 
217 	boolean isLibraryRule(String key) {
218 		return allLibraryRules.containsKey(key);
219 	}
220 
221 	/**
222 	 * do not use remove on this one. Will stringToStructList problems
223 	 * 
224 	 * @return an iterator of all the dynamic predicate indicators in the
225 	 *         Database.
226 	 */
227 	Iterator dynamicPredicateIndicators() {
228 		return dynamicDBase.keySet().iterator();
229 	}
230 
231 	Library consultLib(Library lib) throws PrologException {
232 
233 		ClauseDatabase theoryAssociated = new ClauseDatabase();
234 		for (Iterator it = new Parser(lib.getTheory(), engine).iterator(); it.hasNext();) {
235 			Struct d = (Struct) it.next();
236 			if (runDirective(d))
237 				continue;
238 			Clause cl = BuiltIn.convertTermToClause(d);
239 			theoryAssociated.addLast(cl.head.predicateIndicator, cl);
240 			allLibraryRules.addLast(cl.head.predicateIndicator, cl);
241 		}
242 		librariesToRules.put(lib, theoryAssociated);
243 		return lib;
244 	}
245 
246 	Library unconsultLib(Library lib) {
247 		lib.dismiss();
248 		ClauseDatabase removed = (ClauseDatabase) librariesToRules.remove(lib);
249 		for (Iterator it = removed.keySet().iterator(); it.hasNext();) {
250 			String predInfo = (String) it.next();
251 			List toBeRemoved = (List) removed.get(predInfo);
252 			List parentList = allLibraryRules.getPredicates(predInfo);
253 			for (int i = 0; i < toBeRemoved.size(); i++)
254 				parentList.remove(toBeRemoved.get(i));
255 		}
256 		return lib;
257 	}
258 
259 	Library getLibrary(String name) {
260 		for (Iterator it = getCurrentLibraries(); it.hasNext();) {
261 			Library lib = (Library) it.next();
262 			if (name.equals(lib.getName()))
263 				return lib;
264 		}
265 		return null;
266 	}
267 
268 	/**
269 	 * @return the names of the libraries currently loaded
270 	 */
271 	Iterator getCurrentLibraries() {
272 		return librariesToRules.keySet().iterator();
273 	}
274 }