package org.rascalmpl.library.experiments.Compiler.RVM.Interpreter;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.rascalmpl.debug.IRascalMonitor;
import org.rascalmpl.interpreter.types.FunctionType;
import org.rascalmpl.interpreter.types.RascalTypeFactory;
import org.rascalmpl.value.IAnnotatable;
import org.rascalmpl.value.IConstructor;
import org.rascalmpl.value.IExternalValue;
import org.rascalmpl.value.IValue;
import org.rascalmpl.value.IWithKeywordParameters;
import org.rascalmpl.value.exceptions.IllegalOperationException;
import org.rascalmpl.value.impl.AbstractExternalValue;
import org.rascalmpl.value.type.Type;
import org.rascalmpl.value.type.TypeFactory;
import org.rascalmpl.value.visitors.IValueVisitor;
public class OverloadedFunctionInstance implements ICallableCompiledValue, IExternalValue {
final int[] functions;
private final int[] constructors;
final Frame env;
private Type type;
private Function[] functionStore;
private List<Type> constructorStore;
final RVMCore rvm;
public OverloadedFunctionInstance(final int[] functions, final int[] constructors, final Frame env,
final Function[] functionStore, final List<Type> constructorStore, final RVMCore rvm) {
this.functions = functions;
this.constructors = constructors;
this.env = env;
this.functionStore = functionStore;
this.constructorStore = constructorStore;
this.rvm = rvm;
}
public int[] getFunctions() {
return functions;
}
int[] getConstructors() {
return constructors;
}
int getArity(){
if(functions.length > 0){
return functionStore[functions[0]].nformals;
}
if(constructors.length > 0){
return constructorStore.get(constructors[0]).getArity();
}
throw new RuntimeException("Cannot get arity without functions and constructors");
}
public String toString(){
StringBuilder sb = new StringBuilder("OverloadedFunctionInstance[");
if(getFunctions().length > 0){
sb.append("functions:");
for(int i = 0; i < getFunctions().length; i++){
int fi = getFunctions()[i];
sb.append(" ").append(functionStore[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 OverloadedFunctionInstance computeOverloadedFunctionInstance(final int[] functions, final int[] constructors, final Frame cf, final int scopeIn,
final Function[] functionStore, final List<Type> constructorStore, final RVMCore rvm) {
for(Frame env = cf; env != null; env = env.previousScope) {
if (env.scopeId == scopeIn) {
return new OverloadedFunctionInstance(functions, constructors, env, functionStore, constructorStore, rvm);
}
}
throw new CompilerError("Could not find a matching scope when computing a nested overloaded function instance: " + scopeIn, rvm.getStdErr(), cf);
}
@Override
public Type getType() {
// TODO: this information should probably be available statically?
if(this.type != null) {
return this.type;
}
Set<FunctionType> types = new HashSet<FunctionType>();
for(int fun : this.getFunctions()) {
types.add((FunctionType) functionStore[fun].ftype);
}
for(int constr : this.getConstructors()) {
Type type = constructorStore.get(constr);
// TODO: void type for the keyword parameters is not right. They should be retrievable from a type store dynamically.
types.add((FunctionType) RascalTypeFactory.getInstance().functionType(type.getAbstractDataType(), type.getFieldTypes(), TypeFactory.getInstance().voidType()));
}
this.type = RascalTypeFactory.getInstance().overloadedFunctionType(types);
return this.type;
}
@Override
public <T, E extends Throwable> T accept(IValueVisitor<T, E> v) throws E {
return v.visitExternal((IExternalValue) this);
}
@Override
public boolean isEqual(IValue other) {
return this == other;
}
@Override
public boolean isAnnotatable() {
return false;
}
@Override
public IAnnotatable<? extends IValue> asAnnotatable() {
// TODO Auto-generated method stub
return null;
}
@Override
public boolean mayHaveKeywordParameters() {
return false;
}
@Override
public IWithKeywordParameters<? extends IValue> asWithKeywordParameters() {
throw new IllegalOperationException("Cannot be viewed as with keyword parameters", getType());
}
@Override
public IConstructor encodeAsConstructor() {
return AbstractExternalValue.encodeAsConstructor(this);
}
@Override
public IValue call(IRascalMonitor monitor, Type[] argTypes, IValue[] argValues, Map<String, IValue> keyArgValues) {
return rvm.executeRVMFunction(this, argValues, keyArgValues);
}
@Override
public IValue call(Type[] argTypes, IValue[] argValues, Map<String, IValue> keyArgValues) {
return call(rvm.getMonitor(), argTypes, argValues, keyArgValues);
}
}