package cn.liutils.ripple;
import java.util.HashMap;
import cn.liutils.ripple.RippleException.RippleRuntimeException;
/**
* A wrapper for Java function injected into a Ripple program.
* @author acaly
*
*/
public abstract class NativeFunction implements IFunction {
public class NativeFunctionFrame {
private Object[] args;
NativeFunctionFrame(Object[] args) {
this.args = args;
}
public Object getArgument(String name) {
Integer id = parameterMap.get(name);
if (id == null) {
throw new RippleRuntimeException("Parameter not found");
}
return args[id];
}
public Object getArgument(int id) {
if (id < 0 || id >= args.length) {
throw new RippleRuntimeException("Invalid parameter index");
}
return args[id];
}
public int getIntArgument(String name) {
return Calculation.castInt(getArgument(name));
}
public double getDoubleArgument(String name) {
return Calculation.castDouble(getArgument(name));
}
public boolean getBooleanArgument(String name) {
return Calculation.castBoolean(getArgument(name));
}
public int getIntArgument(int id) {
return Calculation.castInt(getArgument(id));
}
public double getDoubleArgument(int id) {
return Calculation.castDouble(getArgument(id));
}
public boolean getBooleanArgument(int id) {
return Calculation.castBoolean(getArgument(id));
}
//get value or get function can also be added here if really needed
}
private ScriptProgram env;
private Path functionPath;
private final HashMap<String, Integer> parameterMap;
protected NativeFunction(String[] parameters) {
this.parameterMap = new HashMap();
for (int i = 0; i < parameters.length; ++i) {
parameterMap.put(parameters[i], i);
}
}
@Override
public Object call(Object[] args) {
if (args.length != parameterMap.size()) {
throw new RippleRuntimeException("Invalid argument count for function " + functionPath.path + ". " +
parameterMap.size() + " expected, " + args.length + " received.");
}
for (Object arg : args) {
if (!Calculation.checkType(arg)) {
throw new RippleRuntimeException("Invalid argument type for function " + functionPath.path + ".");
}
}
NativeFunctionFrame frame = new NativeFunctionFrame(args);
Object ret = call(frame);
if (!Calculation.checkType(ret)) {
throw new RippleRuntimeException("Invalid return value");
}
return ret;
}
void bind(ScriptProgram env, Path path) {
if (this.env != null) {
throw new RippleRuntimeException("Try to rebind a native function");
}
this.env = env;
this.functionPath = path;
}
int getParamterCount() {
return parameterMap.size();
}
protected abstract Object call(NativeFunctionFrame frame);
}