LibraryAndTheoryManager.java
/*
* #%L
* prolobjectlink-jpi-jtrolog
* %%
* Copyright (C) 2012 - 2018 WorkLogic Project
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 2.1 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Lesser Public License for more details.
*
* You should have received a copy of the GNU General Lesser Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/lgpl-2.1.html>.
* #L%
*/
package jTrolog.engine;
import jTrolog.errors.PrologException;
import jTrolog.parser.Parser;
import jTrolog.lib.Library;
import jTrolog.lib.BuiltIn;
import jTrolog.terms.Struct;
import jTrolog.terms.Term;
import jTrolog.terms.Clause;
import java.io.Serializable;
import java.util.*;
import java.lang.reflect.InvocationTargetException;
/**
* <p>
* This class defines the Library and Theory Manager who manages the libraries
* and clauses/theory often referred to as the Prolog database. The theory (as a
* set of clauses) are stored in the ClauseDatabase which in essence is a
* HashMap grouped by functor/arity.
* </p>
* <p>
* The LibraryAndTheoryManager functions logically, as prescribed by ISO
* Standard 7.5.4 section. The effects of assertions and retractions shall not
* be undone if the program subsequently backtracks over the assert or retract
* call, as prescribed by ISO Standard 7.7.9 section.
* </p>
* <p>
* To use the LibraryAndTheoryManager one should primarily use the methods
* assertA, assertZ, consult, retract, abolish and find.
* </p>
* rewritten by:
*
* @author ivar.orstavik@hist.no
*/
@SuppressWarnings({ "rawtypes", "unchecked","serial" })
class LibraryAndTheoryManager implements Serializable {
private ClauseDatabase dynamicDBase;
private ClauseDatabase allLibraryRules;
private LinkedHashMap librariesToRules;
private Prolog engine;
String lastConsultedTheory;
LibraryAndTheoryManager(Prolog vm) {
dynamicDBase = new ClauseDatabase();
librariesToRules = new LinkedHashMap();
allLibraryRules = new ClauseDatabase();
lastConsultedTheory = "";
engine = vm;
}
/**
* inserting of a clause at the head of the dbase
*/
void assertA(Clause clause, String index) throws PrologException {
dynamicDBase.addFirst(index, clause);
}
/**
* inserting of a clause at the end of the dbase
*/
void assertZ(Clause clause, String index) throws PrologException {
dynamicDBase.addLast(index, clause);
}
/**
* removing from dbase the first clause with head unifying with clause (m if
* a free substitution index and t is the first free timestamp)
*/
Struct retract(Struct clause, String index) throws PrologException {
LinkedList family = (LinkedList) dynamicDBase.get(index);
if (family == null)
return null;
for (Iterator it = family.iterator(); it.hasNext();) {
Clause d = (Clause) it.next();
if (Prolog.match(clause, d.original)) {
it.remove();
return d.original;
}
}
return null;
}
/**
* removes all clauses matching the given signature from the dynamic dbase
*/
List abolish(String index) throws PrologException {
return dynamicDBase.abolish(index);
}
/**
* registers a predicate indicator as known
*/
public void setDynamic(String index) {
LinkedList family = (LinkedList) dynamicDBase.get(index);
if (family != null)
return;
dynamicDBase.addFirst(index, Term.emptyList);
family = (LinkedList) dynamicDBase.get(index);
for (Iterator it = family.iterator(); it.hasNext();) {
it.next();
it.remove();
}
}
/**
* Returns a family of clauses with functor and arity equals to the functor
* and arity of the term passed as a parameter
*/
List find(String predIndicator) throws PrologException {
List dynamics = dynamicDBase.getPredicatesIterator(predIndicator);
return dynamics != null ? dynamics : allLibraryRules.getPredicatesIterator(predIndicator);
}
/**
* Consults a theory.
*
* @param theory
* theory to add
* @throws PrologException
*/
void consult(String theory) throws PrologException {
lastConsultedTheory = theory;
// iterate all clauses in theory and assert them
for (Iterator it = new Parser(theory, engine).iterator(); it.hasNext();) {
Struct d = (Struct) it.next();
if (runDirective(d))
continue;
// d = BuiltIn.convertTermToClause(d);
Clause cl = BuiltIn.convertTermToClause(d);
assertZ(cl, cl.head.predicateIndicator);
}
}
/**
* Clears the clause dbase.
*/
void clear() {
dynamicDBase.clear();
}
private boolean runDirective(Struct c) {
if (c.predicateIndicator != Parser.singleClauseSignature)
return false;
Term dir = c.getArg(0);
if (!(dir instanceof Struct))
return false;
try {
try {
PrimitiveInfo directive = engine.getPrimitive((Struct) dir);
if (directive == null)
engine.warn("The directive " + ((Struct) dir).predicateIndicator + " is unknown.");
else {
Object[] args = new Object[((Struct) dir).arity + 1];
args[0] = new BindingsTable();
for (int i = 0; i < ((Struct) dir).arity; i++)
args[i + 1] = ((Struct) dir).getArg(i);
Prolog.evalPrimitive(directive, args);
}
} catch (InvocationTargetException e) {
Throwable cause = e;
while (cause instanceof InvocationTargetException)
cause = cause.getCause();
throw cause;
}
} catch (Throwable cause) {
engine.warn("An exception has been thrown during the execution of the " + ((Struct) dir).predicateIndicator + " directive.\n" + cause.getMessage());
}
return true;
}
/**
* Gets current theory
*
* @param onlyDynamic
* if true, fetches only dynamic clauses
*/
public String getTheory(boolean onlyDynamic) {
if (onlyDynamic)
return dynamicDBase.toString();
return dynamicDBase.toString() + "\n\n" + allLibraryRules.toString();
}
/**
* Gets last consulted theory
*
* @return last theory
*/
String getLastConsultedTheory() {
return lastConsultedTheory;
}
boolean isLibraryRule(String key) {
return allLibraryRules.containsKey(key);
}
/**
* do not use remove on this one. Will stringToStructList problems
*
* @return an iterator of all the dynamic predicate indicators in the
* Database.
*/
Iterator dynamicPredicateIndicators() {
return dynamicDBase.keySet().iterator();
}
Library consultLib(Library lib) throws PrologException {
ClauseDatabase theoryAssociated = new ClauseDatabase();
for (Iterator it = new Parser(lib.getTheory(), engine).iterator(); it.hasNext();) {
Struct d = (Struct) it.next();
if (runDirective(d))
continue;
Clause cl = BuiltIn.convertTermToClause(d);
theoryAssociated.addLast(cl.head.predicateIndicator, cl);
allLibraryRules.addLast(cl.head.predicateIndicator, cl);
}
librariesToRules.put(lib, theoryAssociated);
return lib;
}
Library unconsultLib(Library lib) {
lib.dismiss();
ClauseDatabase removed = (ClauseDatabase) librariesToRules.remove(lib);
for (Iterator it = removed.keySet().iterator(); it.hasNext();) {
String predInfo = (String) it.next();
List toBeRemoved = (List) removed.get(predInfo);
List parentList = allLibraryRules.getPredicates(predInfo);
for (int i = 0; i < toBeRemoved.size(); i++)
parentList.remove(toBeRemoved.get(i));
}
return lib;
}
Library getLibrary(String name) {
for (Iterator it = getCurrentLibraries(); it.hasNext();) {
Library lib = (Library) it.next();
if (name.equals(lib.getName()))
return lib;
}
return null;
}
/**
* @return the names of the libraries currently loaded
*/
Iterator getCurrentLibraries() {
return librariesToRules.keySet().iterator();
}
}