package org.rascalmpl.library.experiments.Compiler.RVM.Interpreter;
import java.util.Map;
import org.rascalmpl.debug.IRascalMonitor;
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.visitors.IValueVisitor;
public class FunctionInstance implements ICallableCompiledValue, IExternalValue {
public final Function function;
final Frame env;
final RVMCore rvm;
/*
* Records arguments in case of partial parameter binding
*/
Object[] args;
public int next = 0;
public FunctionInstance(final Function function, final Frame env, final RVMCore rvm) {
this.function = function;
this.env = env;
this.rvm = rvm;
}
/**
* Assumption: scopeIn != -1;
*/
public static FunctionInstance computeFunctionInstance(final Function function, final Frame cf, final int scopeIn, final RVMCore rvm) {
assert scopeIn != -1;
for(Frame env = cf; env != null; env = env.previousScope) {
if (env.scopeId == scopeIn) {
return new FunctionInstance(function, env, rvm);
}
}
System.err.println("computeFunctionInstance " + function.name + ", scopeIn=" + scopeIn);
System.err.println("Searched scopes:");
for(Frame env = cf; env != null; env = env.previousScope) {
System.err.println(env.scopeId);
}
throw new CompilerError("Inside " + cf.function.name + " (" + cf.src + ") and scope " + scopeIn + ": cannot find matching scope when looking for nested function " + function.name, rvm.getStdErr(), cf);
}
/**
* Assumption: arity <= function.nformals
*/
public static FunctionInstance applyPartial(final Function function, final Frame env, final RVMCore rvm, final int arity, final Object[] stack, final int sp) {
assert arity <= function.nformals;
FunctionInstance fun_instance = new FunctionInstance(function, env, rvm);
if(arity == 0) {
return fun_instance;
}
fun_instance.args = new Object[function.nformals];
int start = sp - arity;
for(int i = 0; i < arity; i++) {
fun_instance.args[fun_instance.next++] = stack[start + i];
}
return fun_instance;
}
/**
* Assumption: next + arity <= function.nformals
*/
public FunctionInstance applyPartial(final int arity, final Object[] stack, final int sp) {
assert next + arity <= function.nformals;
if(arity == 0) {
return this;
}
FunctionInstance fun_instance = this.copy();
int start = sp - arity;
for(int i = 0; i < arity; i++) {
fun_instance.args[fun_instance.next++] = stack[start + i];
}
return fun_instance;
}
private FunctionInstance copy() {
FunctionInstance fun_instance = new FunctionInstance(function, env, rvm);
if(args != null) {
fun_instance.args = args.clone();
fun_instance.next = next;
} else {
fun_instance.args = new Object[function.nformals];
}
return fun_instance;
}
@Override
public Type getType() {
return function.ftype;
}
@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 IValue call(IRascalMonitor monitor, Type[] argTypes, IValue[] posArgs, Map<String, IValue> kwArgs) {
return rvm.executeRVMFunction(this, posArgs, kwArgs);
}
@Override
public IValue call(Type[] argTypes, IValue[] argValues, Map<String, IValue> keyArgValues) {
return this.call(rvm.getMonitor(), argTypes, argValues, keyArgValues);
}
@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);
}
public String toString() {
return "FunctionInstance[" + function.name + "]";
}
}