JTrologEngine.java
/*
* #%L
* prolobjectlink-jpi-jtrolog
* %%
* Copyright (C) 2019 Prolobjectlink 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 io.github.prolobjectlink.prolog.jtrolog;
import static io.github.prolobjectlink.prolog.PrologLogger.DONT_WORRY;
import static io.github.prolobjectlink.prolog.PrologLogger.FILE_NOT_FOUND;
import static io.github.prolobjectlink.prolog.PrologLogger.INDICATOR_NOT_FOUND;
import static io.github.prolobjectlink.prolog.PrologLogger.IO;
import static io.github.prolobjectlink.prolog.PrologLogger.RUNTIME_ERROR;
import static io.github.prolobjectlink.prolog.PrologLogger.SYNTAX_ERROR;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.Reader;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import io.github.prolobjectlink.prolog.AbstractEngine;
import io.github.prolobjectlink.prolog.Licenses;
import io.github.prolobjectlink.prolog.PrologClause;
import io.github.prolobjectlink.prolog.PrologEngine;
import io.github.prolobjectlink.prolog.PrologIndicator;
import io.github.prolobjectlink.prolog.PrologLogger;
import io.github.prolobjectlink.prolog.PrologOperator;
import io.github.prolobjectlink.prolog.PrologProgram;
import io.github.prolobjectlink.prolog.PrologProvider;
import io.github.prolobjectlink.prolog.PrologQuery;
import io.github.prolobjectlink.prolog.PrologTerm;
import jTrolog.engine.Prolog;
import jTrolog.errors.PrologException;
import jTrolog.lib.BuiltIn;
import jTrolog.lib.IOLibrary;
import jTrolog.lib.Library;
import jTrolog.parser.Parser;
import jTrolog.terms.Clause;
import jTrolog.terms.Struct;
import jTrolog.terms.StructAtom;
import jTrolog.terms.Term;
/**
*
* @author Jose Zalacain
* @since 1.0
*/
public class JTrologEngine extends AbstractEngine implements PrologEngine {
final Prolog engine;
protected JTrologEngine(PrologProvider provider, Prolog engine) {
super(provider);
this.engine = engine;
}
public void consult(String path) {
engine.clearTheory();
include(path);
}
public void consult(Reader reader) {
engine.clearTheory();
include(reader);
}
public void include(String path) {
try {
InputStream is = new FileInputStream(path);
engine.addTheory(IOLibrary.readStream(is));
} catch (FileNotFoundException e) {
getLogger().warn(getClass(), FILE_NOT_FOUND + path, e);
} catch (PrologException e) {
getLogger().error(getClass(), SYNTAX_ERROR + path, e);
} catch (IOException e) {
getLogger().warn(getClass(), IO + path, e);
}
}
public void include(Reader reader) {
BufferedReader bfr = new BufferedReader(reader);
StringBuilder script = new StringBuilder();
try {
String line = bfr.readLine();
while (line != null) {
script.append(line);
script.append("\n");
line = bfr.readLine();
}
engine.addTheory("" + script + "");
} catch (PrologException e) {
getLogger().error(getClass(), SYNTAX_ERROR + script, e);
} catch (IOException e) {
getLogger().warn(getClass(), IO + script, e);
}
}
public void persist(String path) {
PrintWriter writer = null;
try {
writer = new PrintWriter(path);
writer.write(engine.getTheory());
} catch (IOException e) {
getLogger().warn(getClass(), IO + path, e);
getLogger().info(getClass(), DONT_WORRY + path);
} finally {
if (writer != null) {
writer.close();
}
}
}
public void abolish(String functor, int arity) {
String pi = functor + "/" + arity;
try {
engine.abolish(pi);
} catch (PrologException e) {
getLogger().error(getClass(), INDICATOR_NOT_FOUND, e);
}
}
private boolean exist(Clause clause) {
String name = clause.head.name;
StructAtom functor = new StructAtom(name);
String key = functor + "/" + clause.head.arity;
Iterator<?> i = engine.dynamicPredicateIndicators();
while (i.hasNext()) {
String predIndicator = (String) i.next();
if (predIndicator.equals(key)) {
try {
List<?> list = engine.find(predIndicator);
for (Object object : list) {
if (object instanceof Clause) {
Clause iclause = (Clause) object;
if (iclause.head.equals(clause.head)) {
Struct[] xclausetail = iclause.tail.length > 0 ? iclause.tail
: new Struct[] { (Struct) Term.TRUE };
Struct[] yclausetail = clause.tail.length > 0 ? clause.tail
: new Struct[] { (Struct) Term.TRUE };
if (xclausetail.length != yclausetail.length) {
return false;
}
for (int j = 0; j < yclausetail.length; j++) {
if (!xclausetail[j].equals(yclausetail[j])) {
return false;
}
}
return true;
}
}
}
} catch (PrologException e) {
getLogger().error(getClass(), INDICATOR_NOT_FOUND, e);
}
}
}
return false;
}
public void asserta(String stringClause) {
try {
Term term = new Parser(stringClause).nextTerm(false);
asserta(BuiltIn.convertTermToClause(term));
} catch (PrologException e) {
getLogger().error(getClass(), SYNTAX_ERROR + stringClause, e);
}
}
@Override
public void asserta(PrologTerm term) {
asserta("" + term + "");
}
public void asserta(PrologTerm head, PrologTerm... body) {
Struct h = fromTerm(head, Struct.class);
Struct[] b = new Struct[body.length];
for (int i = 0; i < body.length; i++) {
b[i] = fromTerm(body[i], Struct.class);
}
Struct o = fromTerm(head, body, Struct.class);
asserta(new Clause(b, h, o));
}
private void asserta(Clause clause) {
if (!exist(clause)) {
try {
engine.assertA(clause);
} catch (PrologException e) {
getLogger().error(getClass(), RUNTIME_ERROR, e);
}
}
}
public void assertz(String stringClause) {
try {
Term term = new Parser(stringClause).nextTerm(false);
assertz(BuiltIn.convertTermToClause(term));
} catch (PrologException e) {
getLogger().error(getClass(), SYNTAX_ERROR + stringClause, e);
}
}
@Override
public void assertz(PrologTerm term) {
assertz("" + term + "");
}
public void assertz(PrologTerm head, PrologTerm... body) {
Struct h = fromTerm(head, Struct.class);
Struct[] b = new Struct[body.length];
for (int i = 0; i < body.length; i++) {
b[i] = fromTerm(body[i], Struct.class);
}
Struct o = fromTerm(head, body, Struct.class);
assertz(new Clause(b, h, o));
}
private void assertz(Clause clause) {
if (!exist(clause)) {
try {
engine.assertZ(clause);
} catch (PrologException e) {
getLogger().error(getClass(), RUNTIME_ERROR, e);
}
}
}
public boolean clause(String stringClause) {
try {
Term term = new Parser(stringClause).nextTerm(false);
return clause(BuiltIn.convertTermToClause(term));
} catch (PrologException e) {
getLogger().error(getClass(), SYNTAX_ERROR + stringClause, e);
}
return false;
}
@Override
public boolean clause(PrologTerm term) {
return clause("" + term + "");
}
public boolean clause(PrologTerm head, PrologTerm... body) {
Struct h = fromTerm(head, Struct.class);
Struct[] b = new Struct[body.length];
for (int i = 0; i < body.length; i++) {
b[i] = fromTerm(body[i], Struct.class);
}
Struct o = fromTerm(head, body, Struct.class);
return clause(new Clause(b, h, o));
}
private boolean clause(Clause clause) {
String key = clause.head.name + "/" + clause.head.arity;
Iterator<?> i = engine.dynamicPredicateIndicators();
while (i.hasNext()) {
String predIndicator = (String) i.next();
if (predIndicator.equals(key)) {
try {
List<?> list = engine.find(predIndicator);
for (Object object : list) {
if (object instanceof Clause) {
Clause c = (Clause) object;
if (Prolog.match(c.original, clause.original)) {
return true;
}
}
}
} catch (PrologException e) {
getLogger().error(getClass(), INDICATOR_NOT_FOUND + predIndicator, e);
}
}
}
return false;
}
public void retract(String stringClause) {
try {
Term term = new Parser(stringClause).nextTerm(false);
retract(BuiltIn.convertTermToClause(term));
} catch (PrologException e) {
getLogger().error(getClass(), SYNTAX_ERROR + stringClause, e);
}
}
@Override
public void retract(PrologTerm term) {
retract("" + term + "");
}
public void retract(PrologTerm head, PrologTerm... body) {
Struct h = fromTerm(head, Struct.class);
Struct[] b = new Struct[body.length];
for (int i = 0; i < body.length; i++) {
b[i] = fromTerm(body[i], Struct.class);
}
Struct o = fromTerm(head, body, Struct.class);
retract(new Clause(b, h, o));
}
private void retract(Clause clause) {
try {
engine.retract(clause.original);
} catch (PrologException e) {
getLogger().error(getClass(), RUNTIME_ERROR, e);
}
}
@Override
public PrologQuery query(PrologTerm goal) {
return new JTrologQuery(this, goal);
}
public PrologQuery query(String stringQuery) {
return new JTrologQuery(this, stringQuery);
}
public PrologQuery query(PrologTerm[] terms) {
return new JTrologQuery(this, terms);
}
public PrologQuery query(PrologTerm term, PrologTerm... terms) {
return new JTrologQuery(this, term, terms);
}
public void operator(int priority, String specifier, String operator) {
engine.opNew(operator, specifier, priority);
}
public boolean currentPredicate(String functor, int arity) {
String key = Parser.wrapAtom(functor) + "/" + arity;
// supported built-ins
boolean isBuiltin = engine.hasPrimitive(key) || engine.hasPrimitiveExp(key);
// user defined predicates
if (!isBuiltin) {
try {
if (!engine.find(key).isEmpty()) {
return true;
}
} catch (PrologException e) {
getLogger().error(getClass(), PrologLogger.INDICATOR_NOT_FOUND + key, e);
}
}
// not defined
return isBuiltin;
}
public boolean currentOperator(int priority, String specifier, String operator) {
return currentOperators().contains(new JTrologOperator(priority, specifier, operator));
}
public Set<PrologOperator> currentOperators() {
return JTrologUtil.getOperatorSet(engine);
}
public Iterator<PrologClause> iterator() {
Collection<PrologClause> cls = new LinkedList<PrologClause>();
Parser parser = new Parser(engine.getTheory());
for (Iterator<?> iterator = parser.iterator(); iterator.hasNext();) {
Term term = (Term) iterator.next();
if (term instanceof Struct) {
Struct struct = (Struct) term;
if (struct.name.equals(":-") && struct.arity == 2) {
PrologTerm head = toTerm(struct.getArg(0), PrologTerm.class);
PrologTerm body = toTerm(struct.getArg(1), PrologTerm.class);
cls.add(new JTrologClause(provider, head, body, false, false, false));
} else {
PrologTerm head = toTerm(struct, PrologTerm.class);
cls.add(new JTrologClause(provider, head, false, false, false));
}
}
}
return new PrologProgramIterator(cls);
}
public int getProgramSize() {
int counter = 0;
Iterator<?> i = engine.dynamicPredicateIndicators();
while (i.hasNext()) {
String predIndicator = (String) i.next();
try {
List<?> list = engine.find(predIndicator);
counter += list.size();
} catch (PrologException e) {
getLogger().error(getClass(), PrologLogger.INDICATOR_NOT_FOUND + predIndicator, e);
}
}
return counter;
}
@Override
public PrologProgram getProgram() {
return new JTrologProgram(this);
}
public Set<PrologIndicator> getPredicates() {
Set<PrologIndicator> predicates = new HashSet<PrologIndicator>();
Iterator<?> i = engine.dynamicPredicateIndicators();
while (i.hasNext()) {
String predIndicator = (String) i.next();
try {
List<?> list = engine.find(predIndicator);
for (Object object : list) {
if (object instanceof Clause) {
Clause clause = (Clause) object;
String functor = clause.head.name;
int arity = clause.head.arity;
JTrologIndicator p = new JTrologIndicator(functor, arity);
predicates.add(p);
}
}
} catch (PrologException e) {
getLogger().error(getClass(), PrologLogger.INDICATOR_NOT_FOUND + predIndicator, e);
}
}
return predicates;
}
public Set<PrologIndicator> getBuiltIns() {
Iterator<?> libraries = engine.getCurrentLibraries();
Set<PrologIndicator> builtins = new HashSet<PrologIndicator>();
while (libraries.hasNext()) {
Object object = libraries.next();
if (object instanceof Library) {
Library library = (Library) object;
Class<? extends Library> c = library.getClass();
Method[] methods = c.getDeclaredMethods();
String regex = "\\.|\\?|#|[a-z][A-Za-z0-9_]*_[0-9]+";
for (Method method1 : methods) {
String method = method1.getName();
if (method.matches(regex)) {
int j = method.lastIndexOf('_');
String f = method.substring(0, j);
int a = Integer.parseInt(method.substring(j + 1));
builtins.add(new JTrologIndicator(f, a));
}
}
}
}
return builtins;
}
public String getLicense() {
return Licenses.NO_SPECIFIED;
}
public String getVersion() {
return JTrolog.VERSION;
}
public final String getVendor() {
return JTrolog.NAME;
}
public String getName() {
return JTrolog.NAME;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((engine == null) ? 0 : engine.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
JTrologEngine other = (JTrologEngine) obj;
return engine != null && other.engine != null;
}
public void dispose() {
if (engine != null) {
engine.clearTheory();
}
}
public final List<String> verify() {
return Arrays.asList("OK");
}
}