Struct.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.terms;
import jTrolog.parser.Parser;
import jTrolog.terms.EvaluableTerm;
import jTrolog.engine.Prolog;
import java.util.*;
/**
* Struct class represents both compound prolog term and atom term (considered
* as 0-arity compound).
*/
@SuppressWarnings({ "rawtypes", "unchecked","serial","unused" })
public class Struct extends EvaluableTerm {
public final String name;
public final String predicateIndicator;
/** speedup hash map operation */
public final int arity;
public int operatorType = -1; // see Prolog.FX, Prolog.XFX etc.
private Term[] args;
private Var[] varList;
public Var[] getVarList() {
return varList;
}
Struct(String n, int arity, String predIndic) {
type = Term.STRUCT;
name = n;
this.arity = arity;
predicateIndicator = predIndic;
}
/**
* Struct representing an operator
*/
public Struct(String f, Term[] argList, int opType) {
this(f, argList);
operatorType = opType;
}
/**
* Compound struct with an array of arguments
*/
public Struct(String f, Term[] argList) {
this((Parser.removeApices(f)).intern(), argList.length, (Parser.wrapAtom(f) + "/" + argList.length).intern());
args = argList;
varList = (Var[]) getChildrenVarList(args).toArray(new Var[0]);
// prepArrays();
}
/**
* Gets the i-th element of this structure
*
* No bound check is done
*/
public Term getArg(int index) {
return args[index];
}
public int getOperatorType() {
return operatorType;
}
private static List getChildrenVarList(Term[] args) {
List findings = new ArrayList();
for (int i = 0; i < args.length; i++) {
Term arg = args[i];
if (arg instanceof Var)
findings.add(arg);
else if (arg instanceof Struct) {
Var[] childsVars = ((Struct) arg).varList;
if (childsVars != null && childsVars.length > 0)
findings.addAll(Arrays.asList(childsVars));
}
}
return findings;
}
/**
* Gets the string representation of this structure
*
* Specific representations are provided for lists and atoms. Names starting
* with upper case letter are enclosed in apices.
*/
public String toString() {
return predicateIndicator == Parser.listSignature ? toStringList(false) : toStringImpl(false);
}
public String toStringList(boolean small) {
StringBuffer res = new StringBuffer("[");
boolean firstPass = true;
int stopPrinting = Integer.MAX_VALUE;
for (Iterator it = iterator(this); it.hasNext();) {
if (small) {
if (stopPrinting-- == 0) {
Term last = (Term) it.next();
for (; it.hasNext(); last = (Term) it.next())
;
if (last.equals(emptyList))
return res.append(" ... ").append("]").toString();
return res.append(" ... ").append("|").append(last.toStringSmall()).append("]").toString();
}
}
Term child = (Term) it.next();
if (!it.hasNext()) { // last child
if (child.equals(emptyList))
return res.append(']').toString();
return res.append('|').append(small ? child.toStringSmall() : child.toString()).append(']').toString();
}
if (firstPass)
firstPass = false;
else
res.append(", ");
res.append(small ? child.toStringSmall() : child.toString());
}
throw new RuntimeException("bug");
}
public String toStringSmall() {
return predicateIndicator == Parser.listSignature ? toStringList(true) : toStringImpl(true);
}
private String toStringImpl(boolean small) {
if (predicateIndicator == Parser.commaSignature) {
String a = small ? getArg(0).toStringSmall() : getArg(0).toString();
String b = small ? getArg(1).toStringSmall() : getArg(1).toString();
return a + name + " " + b;
}
int opType = getOperatorType();
if (opType == Prolog.XFX || opType == Prolog.YFX || opType == Prolog.XFY) {
String a = small ? getArg(0).toStringSmall() : getArg(0).toString();
String b = small ? getArg(1).toStringSmall() : getArg(1).toString();
return a + " " + name + " " + b;
}
if (opType == Prolog.XF || opType == Prolog.YF) {
String a = small ? getArg(0).toStringSmall() : getArg(0).toString();
return a + " " + name;
}
if (opType == Prolog.FX || opType == Prolog.FY) {
String a = small ? getArg(0).toStringSmall() : getArg(0).toString();
return name + " " + a;
}
if (name.equals("{}")) {
if (arity == 0)
return name;
if (arity == 1)
return "{" + (small ? getArg(0).toStringSmall() : getArg(0).toString()) + "}";
}
StringBuffer res = new StringBuffer(Parser.wrapAtom(name));
res.append("(");
for (int i = 0; i < arity; i++) {
Term arg = getArg(i);
if (arg instanceof Struct && ((Struct) arg).predicateIndicator == Parser.commaSignature)
res.append("(").append(small ? arg.toStringSmall() : arg.toString()).append(")");
else
res.append(small ? arg.toStringSmall() : arg.toString());
if (i < arity - 1)
res.append(", ");
}
res.append(")");
return res.toString();
}
public boolean equals(Object t) {
if (!(t instanceof Struct))
return false;
Struct other = (Struct) t;
if (!predicateIndicator.equals(other.predicateIndicator))
return false;
// return true;
Struct s1 = (Struct) t;
if (arity != s1.arity)
return false;
for (int i = 0; i < s1.arity; i++) {
if (!getArg(i).equals(s1.getArg(i)))
return false;
}
return true;
}
public static Iterator iterator(Struct structList) {
final Struct origin = (Struct) (structList instanceof Wrapper ? ((Wrapper) structList).getBasis() : structList);
Iterator it = new ListIterator(origin);
if (structList instanceof Wrapper)
return new Wrapper.WrappedIterator(it, ((Wrapper) structList).getContext());
return it;
}
private void prepArrays() {
// give me my sizzzzze!
int size = 1; // count me in
for (int i = 0; i < arity; i++) {
Term arg = args[i];
if (arg instanceof Struct && ((Struct) arg).arity > 0)
size += ((Struct) arg).prePost.length;
else
size++;
}
prePost = new int[size];
tree = new Term[size];
int pos = 0;
prePost[pos] = size - 1;
tree[pos] = this;
upDateChild(pos++);
int position = 0;
for (int i = 0; i < arity; i++) {
Term child = getArg(i);
if (child instanceof Struct && ((Struct) child).arity > 0) {
Struct cs1 = (Struct) child;
Term[] valuesArr = cs1.tree;
int[] prePostArr = cs1.prePost;
int childSize = valuesArr.length;
for (int j = 0; j < childSize; j++) {
this.prePost[pos] = prePostArr[j] + position;
this.tree[pos] = valuesArr[j];
upDateChild(pos++);
}
position += childSize;
} else { // atoms and numbers and vars
prePost[pos] = position++;
tree[pos] = child;
upDateChild(pos++);
}
}
}
private void upDateChild(int i) {
Term child = tree[i];
child.tree = tree;
child.prePost = prePost;
child.pos = i;
}
}