Function.java
package progen.kernel.functions;
import java.io.Serializable;
import java.util.List;
import java.util.Map;
import progen.context.ProGenContext;
import progen.kernel.grammar.FunctionNotFoundException;
import progen.kernel.tree.Node;
import progen.userprogram.UserProgram;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
/**
* Clase abstracta que define los métodos necesarios para acceder a las
* distintas funciones que se definan en ProGen.
*
* @author jirsis
* @since 2.0
*/
public abstract class Function implements Comparable<Function>, Serializable {
private static final long serialVersionUID = -7920842332819035400L;
/** Indica la aridad de la función. */
private int arity;
/** Símbolo que identificará a la función. */
private String symbol;
/** Tipo de retorno que devolverá la función. */
private Object returnType;
/** Tipos que admite como parámetros la función. */
private Object [] argsType;
/**
* Constructor por defecto de una función. Recibe la signatura de la misma y
* el símbolo que la identifica.
*
* El formato esperado en la signatura es
* <code>valorDeRetorno$$arg1$$arg2$$...$$argN</code>
*
* @param signature
* Signatura de la función.
* @param symbol
* Símbolo que identificará la función.
*/
public Function(String signature, String symbol) {
String [] args;
this.symbol = symbol;
args = signature.split("\\$\\$");
returnType = args[0];
arity = args.length - 1;
argsType = new Object[arity];
System.arraycopy(args, 1, argsType, 0, arity);
}
/**
* Devuelve la signatura de la función
*
* @return la signatura completa de la función.
*/
public final String getSignature() {
final StringBuffer signature = new StringBuffer();
signature.append(returnType);
for (int i = 0; i < argsType.length; i++) {
signature.append("$$");
signature.append(argsType[i]);
}
return signature.toString();
}
/**
* Devuelve la aridad de la función.
*
* @return la aridad de la función.
*/
public final int getArity() {
return arity;
}
/**
* Devuelve el símbolo de la función.
*
* @return el símbolo de la función.
*/
public final String getSymbol() {
return symbol;
}
/**
* Establece el símbolo que identificará la función.
*
* @param symbol
* El nuevo identificador de la función.
*/
public final void setSymbol(String symbol) {
this.symbol = symbol;
}
/**
* Devuelve el tipo de retorno de la función.
*
* @return el tipo de retorno de la función.
*/
public final Object getReturnType() {
return returnType;
}
public String toString() {
return symbol;
}
/**
* Devuelve el tipo de los argumentos de la función.
*
* @return el tipo de los argumentos de la función.
*/
@SuppressFBWarnings(value = "EI_EXPOSE_REP", justification = "Its is a getter method")
public Object[] getArgsType() {
return argsType;
}
public boolean equals(Object object) {
boolean equals = false;
if (object instanceof Function) {
equals = this.compareTo((Function) object) == 0;
}
return equals;
}
public int hashCode() {
return symbol.hashCode();
}
public int compareTo(Function function) {
return symbol.compareTo(function.getSymbol());
}
/**
* Devuelve una instancia concreta a partir del nombre de la función que se
* desea instanciar.
*
* @param functionName
* el nombre de la función.
* @return una instancia de la función solicitada.
* @throws FunctionNotFoundException
* En caso de que no se encuentre la función en el paquete del
* usuario o en el paquete de funciones de la aplicación, en ese
* orden.
* @throws UndefinedFunctionSetException
* En el caso de instanciar un ADF que no esté definido en el
* function-set correspondiente.
*/
public static final Function load(String functionName){
Function function;
final String classPathProGen = "progen.kernel.functions.";
final String classPathUser = ProGenContext.getOptionalProperty("progen.user.home", classPathProGen);
if (functionName.startsWith("ADF")) {
function = loadFunctionADF(functionName);
} else {
function = loadReagularFunction(functionName, classPathProGen, classPathUser);
}
return function;
}
private static Function loadFunctionADF(String functionName) {
return new ADF(functionName);
}
private static Function loadReagularFunction(String functionName, String classPathProGen, String classPathUser) {
Function function;
try {
function = (Function) Class.forName(classPathUser + functionName).newInstance();
} catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
try {
function = (Function) Class.forName(classPathProGen + functionName).newInstance();
} catch (InstantiationException | IllegalAccessException | ClassNotFoundException e1) {
throw new FunctionNotFoundException(functionName, e1);
}
}
return function;
}
/**
* Comprueba si una función es compatible con otra, es decir, si recibe los
* mismos argumentos y tiene el mismo valor de retorno.
*
* @param function
* La función para comprobar la compatibilidad.
* @return <code>true</code> si es compatible y <code>false</code> si no lo
* es.
*/
public boolean isCompatibleWith(Function function) {
boolean isCompatible = true;
// si las aridades no son distintas, no pueden ser compatibles
if (this.arity == function.arity) {
for (int i = 0; i < arity; i++) {
isCompatible &= argsType[i].equals(function.argsType[i]);
}
} else {
isCompatible = false;
}
// comprobacion del valor de retorno
isCompatible &= returnType.equals(function.returnType);
return isCompatible;
}
/**
* Forma de calcular el valor concreto de la ejecución de una función.
*
* @param arguments
* conjunto de argumentos que se definieron a la hora de crear la
* función.
* @param userProgram
* referencia al dominio creado por el usuario por si necesitara
* utilizar algún método declarado él.
* @param returnAddr
* Valor de retorno de las llamadas a ADFs
* @return El valor de evaluar una función concreta
*/
public abstract Object evaluate(List<Node> arguments, UserProgram userProgram, Map<String, Object> returnAddr);
}