package org.rascalmpl.library.experiments.Compiler.RVM.Interpreter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.rascalmpl.value.IValue;
import org.rascalmpl.value.exceptions.FactTypeUseException;
import org.rascalmpl.value.type.Type;
public class OverloadedFunctionInstanceCall {
private final int[] functions;
private final int[] constructors;
final Frame cf;
final Frame previousScope;
final Type types;
final int arity;
final Object[] stack;
final int sp;
int alternative = 0;
public OverloadedFunctionInstanceCall(final Frame cf, final int[] functions, final int[] constructors, final Frame previousScope, final Type types, final int arity) {
this.cf = cf;
assert functions.length + constructors.length > 0;
assert functions.length == 0 && types == null ? constructors.length > 0 : true;
this.functions = functions;
this.constructors = constructors;
this.previousScope = previousScope;
this.types = types;
this.arity = arity;
this.stack = cf.stack;
this.sp = cf.sp;
}
int[] getFunctions() {
return functions;
}
int[] getConstructors() {
return constructors;
}
public String toString(List<Function> functionStore, List<Type> constructorStore){
StringBuilder sb = new StringBuilder("OverloadedFunctionInstanceCall[");
if(getFunctions().length > 0){
sb.append("functions:");
for(int i = 0; i < getFunctions().length; i++){
int fi = getFunctions()[i];
sb.append(" ").append(functionStore.get(fi).getName()).append("/").append(fi);
}
}
if(getConstructors().length > 0){
if(getFunctions().length > 0){
sb.append("; ");
}
sb.append("constructors:");
for(int i = 0; i < getConstructors().length; i++){
int ci = getConstructors()[i];
sb.append(" ").append(constructorStore.get(ci).getName()).append("/").append(ci);
}
}
sb.append("]");
return sb.toString();
}
/**
* Assumption: scopeIn != -1;
*/
public static OverloadedFunctionInstanceCall computeOverloadedFunctionInstanceCall(final Frame cf, final int[] functions, final int[] constructors, final int scopeIn, final Type types, final int arity) {
assert scopeIn != -1 : "OverloadedFunctionInstanceCall, scopeIn should not be -1";
for(Frame previousScope = cf; previousScope != null; previousScope = previousScope.previousScope) {
if (previousScope.scopeId == scopeIn) {
return new OverloadedFunctionInstanceCall(cf, functions, constructors, previousScope, types, arity);
}
}
throw new CompilerError("Could not find a matching scope when computing a nested overloaded function instance: " + scopeIn, cf);
}
public Frame nextFrame(final Function[] functionStore) {
Function f = this.nextFunction(functionStore);
if(f == null) {
return null;
}
return cf.getFrame(f, previousScope, arity, sp);
}
public Function nextFunction(final Function[] functionStore) {
if(types == null) {
return alternative < getFunctions().length ? functionStore[getFunctions()[alternative++]] : null;
} else {
while(alternative < getFunctions().length) {
Function fun = functionStore[getFunctions()[alternative++]];
for(Type type : types) {
try {
Map<Type,Type> bindings = new HashMap<Type,Type>();
type.match(fun.ftype, bindings);
return fun;
} catch(FactTypeUseException e) {
;
}
}
}
}
return null;
}
public Type nextConstructor(final List<Type> constructorStore) {
if(types == null) {
if(getConstructors().length == 0){
System.err.println("No alternative found for (overloaded) function or constructor;\narity: " + arity + ", previousScope: " + previousScope);
if(getFunctions().length > 0){
System.err.print("Function(s):");
for(int i = 0; i < getFunctions().length; i++){
System.err.print(" " + getFunctions()[i]);
}
System.err.println("");
}
if(getConstructors().length > 0){
System.err.println("Constructor(s):");
for(int i = 0; i < getConstructors().length; i++){
System.err.print(" " + getConstructors()[i]);
}
System.err.println("");
}
}
assert getConstructors().length >= 1;
return constructorStore.get(getConstructors()[0]);
} else {
for(int index : getConstructors()) {
Type constructor = constructorStore.get(index);
for(Type type : types) {
try {
Map<Type,Type> bindings = new HashMap<Type,Type>();
type.match(constructor, bindings);
return constructor;
} catch(FactTypeUseException e) {
;
}
}
}
}
return null;
}
/**
* Assumptions:
* - constructors do not permit var args,
* - only constructors without keyword parameters may be directly called within an overloaded function call,
* - constructors with keyword parameters are indirectly called via companion functions.
*/
public IValue[] getConstructorArguments(final int arity) {
IValue[] args = new IValue[arity];
for(int i = 0; i < arity; i++) {
args[i] = (IValue) stack[sp - this.arity + i];
}
return args;
}
}