package org.rascalmpl.library.experiments.Compiler.RVM.Interpreter;
import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import org.nustaq.serialization.FSTBasicObjectSerializer;
import org.nustaq.serialization.FSTClazzInfo;
import org.nustaq.serialization.FSTClazzInfo.FSTFieldInfo;
import org.nustaq.serialization.FSTObjectInput;
import org.nustaq.serialization.FSTObjectOutput;
import org.rascalmpl.interpreter.types.OverloadedFunctionType;
import org.rascalmpl.value.IValue;
import org.rascalmpl.value.IValueFactory;
import org.rascalmpl.value.type.Type;
import org.rascalmpl.value.type.TypeStore;
import org.rascalmpl.values.uptr.RascalValueFactory;
/**
* Represent one overloaded function given
* - a list of function alternatives
* - a list of constructor alternatives
* - a scope
*
* An overloaded function is created during loading and is consulted at run-time
* to create an OverloadedFunctionInstance for each specific call.
*
*/
public class OverloadedFunction implements Serializable {
private static final long serialVersionUID = -5235184427484318482L;
final String name;
final Type funType;
int[] functions;
final int[] constructors;
final String funIn;
int scopeIn = -1;
boolean allConcreteFunctionArgs = false;
boolean allConcreteConstructorArgs = false;
HashMap<Integer, int[]> filteredFunctions; // Functions and constructors filtered on fingerprint of first argument
HashMap<Integer, int[]> filteredConstructors;
public OverloadedFunction(String name, Type funType, final int[] functions, final int[] constructors, final String funIn) {
if(funIn == null){
System.out.println("OverloadedFunction: funIn is null");
}
this.name = name;
this.funType = funType;
this.functions = functions;
this.constructors = constructors;
this.funIn = funIn;
}
public OverloadedFunction(String name, Type funType, int[] functions, int[] constructors, String funIn,
int scopeIn, boolean allConcreteFunctionArgs, boolean allConcreteConstructorArgs,
HashMap<Integer, int[]> filteredFunctions, HashMap<Integer, int[]> filteredConstructors) {
this.name = name;
this.funType = funType;
this.functions = functions;
this.constructors = constructors;
this.funIn = funIn;
this.scopeIn = scopeIn;
this.allConcreteFunctionArgs = allConcreteFunctionArgs;
this.allConcreteConstructorArgs = allConcreteConstructorArgs;
this.filteredFunctions = filteredFunctions;
this.filteredConstructors = filteredConstructors;
}
public boolean matchesNameAndSignature(String name, Type funType){
if(!this.name.equals(name)){
return false;
}
if(this.funType.comparable(funType)){
return true;
}
if(this.funType instanceof OverloadedFunctionType){
OverloadedFunctionType oft = (OverloadedFunctionType) this.funType;
for(Type ft : oft.getAlternatives()){
if(ft.comparable(funType)){
return true;
}
}
}
return false;
}
public String getName() {
return name;
}
public int getArity(){
return funType.getArity();
}
public void finalize(final Map<String, Integer> functionMap, ArrayList<Function> functionStore, Map<Integer, Integer> indexMap){
if(funIn.length() > 0){ // != null) {
Integer si = functionMap.get(funIn);
if(si == null){ // Give up, containing scope is not included in final RVM image created by loader
return;
}
this.setScopeIn(si);
}
if(indexMap != null){
int nelems = 0;
for(int i = 0; i < functions.length; i++){
Integer newIndex = indexMap.get(functions[i]);
if(newIndex != null){
functions[nelems++] = newIndex;
}
}
if(functions.length > nelems){
int[] newFunctions = new int[nelems];
for(int i = 0; i < nelems; i++){
newFunctions[i] = functions[i];
}
functions = newFunctions;
}
}
// TODO: temp consistency tests
for(int fid : functions){
if(fid < 0 || fid >= functionStore.size()){
System.err.println("OverloadedFunction: function outside functionStore: " + fid);
}
}
// for(int cid : constructors){
// if(cid < 0 || cid >= functionStore.size()){
// System.err.println("OverloadedFunction: constructor outside functionStore: " + cid);
// }
// }
filter(functionStore);
}
void printArray(int[] a){
System.out.print("[ ");for(int i : functions) System.out.print(i + " "); System.out.println("]");
}
boolean compareIntArrays(int[] a, int[] b){
if(a == null && b != null){
System.out.println("Array a null, b is not null");
return false;
}
if(a != null && b == null){
System.out.println("Array a not null, b is null");
return false;
}
if(a == null && b == null){
System.out.println("Array a null, b is null");
return false;
}
if(a.length != b.length){
System.out.println("Different length: " + a.length + " vs " + b.length);
}
for(int i = 0; i < a.length; i++){
if(a[i] != b[i]){
System.out.println("Differ at index " + i);
return false;
}
}
return true;
}
boolean compareIntMaps(HashMap<Integer, int[]> a, HashMap<Integer, int[]> b){
if(a.size() != b.size()){
System.out.println("Different length: " + a.size() + " vs " + b.size());
}
for(int i : a.keySet()){
if(!compareIntArrays(a.get(i), b.get(i))){
System.out.println("Maps differ at index " + i);
return false;
}
}
return true;
}
public boolean comparable(OverloadedFunction other){
if(!compareIntArrays(functions, other.functions)){
System.out.println("functions differ: " + functions + " vs " + other.functions);
printArray(functions); System.out.print(" vs "); printArray(other.functions);
return false;
}
if(!compareIntArrays(constructors, other.constructors)){
System.out.println("constructors differ: " + constructors + " vs " + other.constructors);
printArray(constructors); System.out.print(" vs "); printArray(other.constructors);
return false;
}
if(!funIn.equals(other.funIn)){
System.out.println("funIn differ");
return false;
}
if(getScopeIn() != other.getScopeIn()){
System.out.println("scopeIn differ");
return false;
}
if(allConcreteFunctionArgs != other.allConcreteFunctionArgs){
System.out.println("allConcreteFunctionArgs differ");
return false;
}
if(allConcreteConstructorArgs != other.allConcreteConstructorArgs){
System.out.println("allConcreteConstructorArgs differ");
return false;
}
if(filteredFunctions != null && other.filteredFunctions != null && !compareIntMaps(filteredFunctions, other.filteredFunctions)){
System.out.println("filteredFunctions differ");
return false;
}
if(filteredConstructors != null && other.filteredConstructors != null && !compareIntMaps(filteredConstructors, other.filteredConstructors)){
System.out.println("filteredConstructors differ");
return false;
}
return true;
}
/**
* Get the overloaded alternatives for this function given (first) actual parameter args0
* @param arg0 first actual parameter
* @return list of overloadings
*/
public int[] getFunctions(Object arg0){
if(functions.length <= 1 || !(arg0 instanceof IValue)){
return functions;
}
int fp = ToplevelType.getFingerprint((IValue) arg0, allConcreteFunctionArgs);
int[] funs = filteredFunctions.get(fp);
return funs == null ? filteredFunctions.get(0) : funs;
}
/**
* Get the overloaded constructor alternatives for this function given (first) actual parameter args0
* @param arg0 first actual parameter
* @return list of overloadings
*
* Note: at the moment we do not (yet?) filter constructor alternatives
*/
public int[] getConstructors(Object arg0) {
return constructors;
}
private void filter(ArrayList<Function> functionStore){
filterFunctions(functionStore);
//filterConstructors(rvm);
}
/**
* Preprocess all overloadings to make run-time lookup as fast as possible:
* - All overloads with the same fingerprint are collected and placed in a table.
* - All overloads that (a) map to fingerprint 0 (b) are a default functions are
* are placed at the end of the list of alternatives for each fingerprint.
*
* @param rvm needed for access to the function declarations via rvm.functionStore
*/
private void filterFunctions(ArrayList<Function> functionStore){
if(functions.length > 1){
filteredFunctions = new HashMap<Integer,int[]>();
} else {
return;
}
// Determine whether all first arguments are concrete
allConcreteFunctionArgs = true;
HashMap<Integer, ArrayList<Integer>> filtered = new HashMap<Integer, ArrayList<Integer>>();
for(int fid : functions){
Function fdef = functionStore.get(fid);
if(!fdef.concreteArg){
allConcreteFunctionArgs = false;
}
}
// Collect applicable functions per fingerprint
for(int fid : functions){
Function fdef = functionStore.get(fid);
int fp = fdef.isDefault ? 0 : (allConcreteFunctionArgs ? fdef.concreteFingerprint : fdef.abstractFingerprint);
ArrayList<Integer> alts = filtered.get(fp);
if(alts == null){
alts = new ArrayList<Integer>();
filtered.put(fp, alts);
}
alts.add(fid);
}
// Transform the table into one with the required values of type: int[]
// On the fly attach all default functions to each entry
ArrayList<Integer> defaults = filtered.get(0);
if(defaults == null){
defaults = new ArrayList<Integer>();
filtered.put(0, defaults);
}
int ndefaults = defaults.size();
for(int fp : filtered.keySet()){
ArrayList<Integer> alts = filtered.get(fp);
int nalts = alts.size();
int[] funs = new int[nalts + ndefaults];
for(int i = 0; i < nalts; i++){
funs[i] = alts.get(i);
}
for(int i = 0; i < ndefaults; i++){
funs[nalts + i] = defaults.get(i);
}
filteredFunctions.put(fp, funs);
}
}
// The next four members are needed by the bytecode generator.
public int[] getFunctions() {
return functions;
}
public int[] getConstructors() {
return constructors;
}
public int getScope() {
return getScopeIn() ;
}
public String getScopeFun() {
return funIn ;
}
public String toString(){
StringBuilder sb = new StringBuilder("Overloaded[" + name + ":" + funType + ":");
if(functions.length > 0){
sb.append("functions:");
for(int i = 0; i < functions.length; i++){
sb.append(" ").append(functions[i]);
}
}
if(constructors.length > 0){
if(functions.length > 0){
sb.append("; ");
}
sb.append("constructors:");
for(int i = 0; i < constructors.length; i++){
sb.append(" ").append(constructors[i]);
}
}
sb.append("]");
return sb.toString();
}
public int getScopeIn() {
return scopeIn;
}
public void setScopeIn(int scopeIn) {
this.scopeIn = scopeIn;
}
}
/**
* FSTOverloadedFunctionSerializer: serializer for OverloadedFunction objects
*
*/
class FSTOverloadedFunctionSerializer extends FSTBasicObjectSerializer {
//private static IValueFactory vf;
private static TypeStore store;
public static void initSerialization(IValueFactory vfactory, TypeStore ts){
//vf = vfactory;
store = ts;
store.extendStore(RascalValueFactory.getStore());
}
@Override
public void writeObject(FSTObjectOutput out, Object toWrite,
FSTClazzInfo clzInfo, FSTFieldInfo arg3, int arg4)
throws IOException {
OverloadedFunction ofun = (OverloadedFunction) toWrite;
// String name;
out.writeObject(ofun.name);
// Type funType;
out.writeObject(new FSTSerializableType(ofun.funType));
// int[] functions;
out.writeObject(ofun.functions);
// final int[] constructors;
out.writeObject(ofun.constructors);
// final String funIn;
out.writeObject(ofun.funIn);
// private int scopeIn = -1;
out.writeObject(ofun.scopeIn);
// boolean allConcreteFunctionArgs = false;
out.writeObject(ofun.allConcreteFunctionArgs);
// boolean allConcreteConstructorArgs = false;
out.writeObject(ofun.allConcreteConstructorArgs);
// HashMap<Integer, int[]> filteredFunctions;
out.writeObject(ofun.filteredFunctions);
// HashMap<Integer, int[]> filteredConstructors;
out.writeObject(ofun.filteredConstructors);
}
@Override
public void readObject(FSTObjectInput in, Object toRead, FSTClazzInfo clzInfo, FSTClazzInfo.FSTFieldInfo referencedBy)
{
}
@SuppressWarnings("unchecked")
public Object instantiate(@SuppressWarnings("rawtypes") Class objectClass, FSTObjectInput in, FSTClazzInfo serializationInfo, FSTClazzInfo.FSTFieldInfo referencee, int streamPosition) throws ClassNotFoundException, IOException
{
// String name;
String name = (String) in.readObject();
// Type funType;
Type funType = (Type) in.readObject();
// int[] functions;
int[] functions = (int[]) in.readObject();
// final int[] constructors;
int[] constructors = (int[]) in.readObject();
// final String funIn;
String funIn = (String) in.readObject();
// private int scopeIn = -1;
int scopeIn = (Integer) in.readObject();
// boolean allConcreteFunctionArgs = false;
boolean allConcreteFunctionArgs = (Boolean) in.readObject();
// boolean allConcreteConstructorArgs = false;
boolean allConcreteConstructorArgs = (Boolean) in.readObject();
// HashMap<Integer, int[]> filteredFunctions;
HashMap<Integer, int[]> filteredFunctions = (HashMap<Integer, int[]>) in.readObject();
// HashMap<Integer, int[]> filteredConstructors;
HashMap<Integer, int[]> filteredConstructors = (HashMap<Integer, int[]>) in.readObject();
OverloadedFunction ofun = new OverloadedFunction(name, funType, functions, constructors, funIn, scopeIn, allConcreteFunctionArgs, allConcreteConstructorArgs,
filteredFunctions,filteredConstructors);
return ofun;
}
}