package org.reldb.rel.v0.generator;
import java.util.*;
import org.reldb.rel.exceptions.ExceptionFatal;
import org.reldb.rel.v0.types.Type;
import org.reldb.rel.v0.types.TypeAlpha;
/** This class provides mechanisms to define an object signature and convert it to a string. */
public class OperatorSignature implements Comparable<OperatorSignature> {
private Vector<Type> parameterTypes;
private Vector<String> parameterNames = null;
private Type returnType;
private String name;
public OperatorSignature(String name) {
parameterTypes = new Vector<Type>();
this.name = name;
}
/* Return true if an operator with this signature can be invoked by the specified invocation signature. */
public boolean canBeInvokedBy(OperatorSignature signature) {
if (name == null && signature.name != null)
return false;
if (name != null && signature.name == null)
return false;
if (name != null && signature.name != null && !name.equals(signature.name))
return false;
if (parameterTypes.size() != signature.parameterTypes.size())
return false;
for (int i=0; i<parameterTypes.size(); i++)
if (!parameterTypes.get(i).canAccept(signature.parameterTypes.get(i)))
return false;
return true;
}
/** Return the ranked difference (based on inheritance) between this signature and the specified invocation signature. */
public int getInvocationDistance(OperatorSignature signature) {
if (parameterTypes.size() != signature.parameterTypes.size())
return Integer.MAX_VALUE;
int totalDistance = 0;
for (int i=0; i<parameterTypes.size(); i++) {
if (!signature.parameterTypes.get(i).canAccept(parameterTypes.get(i)))
return Integer.MAX_VALUE;
if (!(parameterTypes.get(i) instanceof TypeAlpha))
totalDistance += 0;
else {
TypeAlpha t = (TypeAlpha)signature.getParameterType(i);
while (t != null && !t.getTypeName().equals(((TypeAlpha)parameterTypes.get(i)).getTypeName())) {
totalDistance += 1;
t = t.getSupertype();
}
}
}
return totalDistance;
}
public String getName() {
return name;
}
/** Return true if this signature might reference more than one operator when taking inheritance and subtyping into account. */
public boolean isPossiblyDynamicDispatch() {
for (Type parmType: parameterTypes)
if (parmType instanceof TypeAlpha)
return true;
return false;
}
public void addParameter(String name, Type t) {
if (name == null)
throw new ExceptionFatal("RS0303: Attempt to define null parameter name.");
if (t == null)
throw new ExceptionFatal("RS0304: Attempt to define null parameter type.");
if (parameterNames == null)
parameterNames = new Vector<String>();
parameterNames.add(name);
parameterTypes.add(t);
}
public void addParameterType(Type t) {
parameterTypes.add(t);
if (t == null)
throw new ExceptionFatal("RS0305: Attempt to define null parameter type.");
}
public int getParmCount() {
return parameterTypes.size();
}
public void setParameterType(int index, Type t) {
if (t == null)
throw new ExceptionFatal("RS0306: Attempt to define null parameter type.");
while (parameterTypes.size() <= index)
parameterTypes.add(null);
parameterTypes.set(index, t);
}
public Type getParameterType(int index) {
return parameterTypes.get(index);
}
public String getParameterName(int index) {
return parameterNames.get(index);
}
public Type[] getParameterTypes() {
return parameterTypes.toArray(new Type[0]);
}
public void setReturnType(Type type) {
returnType = type;
}
public Type getReturnType() {
return returnType;
}
/** Comparison for signature lookup. */
public int compareTo(OperatorSignature o) {
return toRelLookupString().compareToIgnoreCase(o.toRelLookupString());
}
public boolean equals(Object o) {
return compareTo((OperatorSignature)o) == 0;
}
public int hashCode() {
return toRelLookupString().hashCode();
}
public boolean isAnonymous() {
return (name == null);
}
/** Convert to string for display purposes. Includes return type. */
public String toString() {
if (getReturnType() == null)
return toRelLookupString();
return toRelLookupString() + " RETURNS " + getReturnType().getSignature();
}
// Construct signature.
private String toFinalSignature(String parmSignature) {
return (isAnonymous() ? "" : getName()) + "(" + parmSignature + ")";
}
/** Convert to string for native lookup purposes. Does not include return type. */
public String toNativeLookupString() {
String parmSignature = "";
for (Type type: parameterTypes)
parmSignature += (parmSignature.length() == 0) ? type.getClass().getCanonicalName() : (", " + type.getClass().getCanonicalName());
return toFinalSignature(parmSignature);
}
/** Convert to string for Rel operator lookup purposes. Does not include return type. */
public String toRelLookupString() {
String parmSignature = "";
for (Type type: parameterTypes)
parmSignature += (parmSignature.length() == 0) ? type.getSignature() : (", " + type.getSignature());
return toFinalSignature(parmSignature);
}
/** Get operator declaration */
public String getOperatorDeclaration() {
String parmSignature = "";
int nameIndex = 0;
for (Type type: parameterTypes) {
String parmDef = parameterNames.get(nameIndex) + " " + type.getSignature();
parmSignature += (parmSignature.length() == 0) ? parmDef : (", " + parmDef);
nameIndex++;
}
return "OPERATOR " + toFinalSignature(parmSignature) + ((returnType != null) ? " RETURNS " + returnType.getSignature() : "");
}
/** Given a string, convert any non identifier-allowable character to
* an underscore. */
private static String classNameMung(String s) {
char [] strbuf = s.toCharArray();
for (int i=0; i<strbuf.length; i++)
if (!Character.isJavaIdentifierPart(strbuf[i]))
strbuf[i] = '_';
return new String(strbuf);
}
/** Get name for use in producing a Java class name. */
public String getClassSignature() {
String s = "op_" + getName() + "_";
for (int i=0; i<getParmCount(); i++)
s += "_" + classNameMung(getParameterType(i).toString());
return s;
}
}