JplProgram.java
/*
* #%L
* prolobjectlink-jpi-jpl
* %%
* 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.jpl;
import java.util.AbstractSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import io.github.prolobjectlink.prolog.ArrayIterator;
import io.github.prolobjectlink.prolog.PrologClauses;
import io.github.prolobjectlink.prolog.PrologError;
import jpl.Term;
/**
*
* @author Jose Zalacain
* @since 1.0
*/
final class JplProgram extends AbstractSet<List<Term>> {
//
private final JplParser parser = new JplParser();
// program initializations goals
private final List<Term> goals = new LinkedList<Term>();
// list of directives goals
private final List<Term> directives = new LinkedList<Term>();
// program (data base) in read order
private final LinkedHashMap<String, List<Term>> clauses = new LinkedHashMap<String, List<Term>>();
private String getKey(Term clause) {
String key = clause.name();
key += "/" + clause.arity();
if (key.equals(":-/2")) {
key = clause.arg(1).name();
key += "/";
key += clause.arg(1).arity();
}
return key;
}
private String getKey(List<Term> cls) {
String msg = "Empty clause list";
if (!cls.isEmpty()) {
Term t = cls.get(0);
String key = t.name();
key += "/" + t.arity();
return key;
}
throw new PrologError(msg);
}
public List<Term> get(String key) {
return clauses.get(key);
}
public void add(Term clause) {
String key = getKey(clause);
List<Term> family = get(key);
if (family == null) {
family = new LinkedList<Term>();
family.add(clause);
clauses.put(key, family);
} else if (!family.contains(clause)) {
family.add(clause);
}
}
@Override
public boolean add(List<Term> cls) {
String key = getKey(cls);
List<Term> family = get(key);
if (family != null) {
family.addAll(cls);
} else {
clauses.put(key, cls);
}
return true;
}
public void add(JplProgram program) {
goals.addAll(program.getGoals());
clauses.putAll(program.getClauses());
directives.addAll(program.getDirectives());
}
@Override
public boolean remove(Object o) {
if (o instanceof Term) {
Term c = (Term) o;
String key = getKey(c);
List<Term> family = get(key);
if (family != null) {
return family.remove(c);
}
}
else if (o instanceof PrologClauses) {
PrologClauses cs = (PrologClauses) o;
String key = cs.getIndicator();
List<Term> oldFamily = clauses.remove(key);
return oldFamily != null;
}
return false;
}
public boolean remove(Term o) {
if (o instanceof Term) {
String key = getKey(o);
List<Term> family = get(key);
if (family != null) {
return family.remove(o);
}
}
return false;
}
public void push(Term clause) {
String key = getKey(clause);
List<Term> family = clauses.remove(key);
List<Term> cs = new LinkedList<Term>();
if (family != null && !family.contains(clause)) {
cs.add(clause);
for (Term term : family) {
cs.add(term);
}
} else {
cs.add(clause);
}
clauses.put(key, cs);
}
public void removeAll(String key) {
clauses.remove(key);
}
public void removeAll(String functor, int arity) {
removeAll(functor + "/" + arity);
}
public List<Term> getDirectives() {
return directives;
}
public boolean addDirective(Term directive) {
return directives.add(directive);
}
public boolean removeDirective(Term directive) {
return directives.remove(directive);
}
public List<Term> getGoals() {
return goals;
}
public boolean addGoal(Term goal) {
return goals.add(goal);
}
public boolean removeGoal(Term goal) {
return goals.remove(goal);
}
public Set<String> getIndicators() {
return clauses.keySet();
}
public Map<String, List<Term>> getClauses() {
return clauses;
}
@Override
public String toString() {
StringBuilder families = new StringBuilder();
if (!directives.isEmpty()) {
Iterator<Term> i = directives.iterator();
while (i.hasNext()) {
families.append(":-");
families.append(i.next());
families.append('.');
families.append(i.hasNext() ? "\n" : "\n\n");
}
}
if (!clauses.isEmpty()) {
Iterator<List<Term>> i = iterator();
while (i.hasNext()) {
List<Term> l = i.next();
Iterator<Term> j = l.iterator();
while (j.hasNext()) {
Term term = j.next();
String key = term.name();
key += "/" + term.arity();
if (term.arity() == 2 && key.equals(":-/2")) {
Term h = term.arg(1);
Term b = term.arg(2);
families.append(h);
families.append(" :- ");
families.append('\n');
families.append('\t');
Term[] array = parser.parseTerms(b);
Iterator<Term> k = new ArrayIterator<Term>(array);
while (k.hasNext()) {
Term item = k.next();
families.append(item);
if (k.hasNext()) {
families.append(',');
families.append('\n');
families.append('\t');
}
}
} else {
families.append(term);
}
families.append('.');
families.append('\n');
}
if (i.hasNext()) {
families.append('\n');
}
}
}
return "" + families + "";
}
@Override
public Iterator<List<Term>> iterator() {
return clauses.values().iterator();
}
@Override
public int size() {
int size = 0;
Iterator<List<Term>> i = iterator();
while (i.hasNext()) {
List<Term> l = i.next();
Iterator<Term> j = l.iterator();
while (j.hasNext()) {
j.next();
size++;
}
}
return size;
}
@Override
public void clear() {
goals.clear();
clauses.clear();
directives.clear();
}
@Override
public int hashCode() {
final int prime = 31;
int result = super.hashCode();
result = prime * result + clauses.hashCode();
result = prime * result + directives.hashCode();
result = prime * result + goals.hashCode();
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (!super.equals(obj))
return false;
if (getClass() != obj.getClass())
return false;
JplProgram other = (JplProgram) obj;
if (!clauses.equals(other.clauses)) {
return false;
}
if (!directives.equals(other.directives)) {
return false;
}
return goals.equals(other.goals);
}
}