package calculator.interpreter.annotations;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.List;
import net.sf.etl.parsers.SourceLocation;
import calculator.interpreter.AnnotationValue;
import calculator.interpreter.Environment;
import calculator.interpreter.EvalException;
import calculator.interpreter.EvalUtils;
import calculator.interpreter.Function;
import calculator.interpreter.Variable;
/**
* The java method annotation
*/
public class JavaMethodAnnotation extends JavaReflectionProcessor {
/** {@inheritDoc} */
public void process(AnnotationValue annotation, Environment env, Variable var) {
if (annotation.arguments.size() < 2) {
throw new EvalException(annotation.location,
"Wrong number of the arguments for annotation expected at least 2 and found "
+ annotation.arguments);
}
Class<?> c = getClass(annotation, 0);
String methodName = EvalUtils.expectString(annotation.location,
"the field name (the argument " + 1 + ")", annotation.arguments.get(1));
Class<?>[] parameterTypes = new Class[annotation.arguments.size() - 2];
for (int i = 0; i < annotation.arguments.size() - 2; i++) {
parameterTypes[i] = getClass(annotation, i + 2);
}
try {
Method method = c.getMethod(methodName, parameterTypes);
var.bind(annotation.location, new MethodFunction(method));
} catch (Exception e) {
throw new EvalException(annotation.location, "The method " + methodName
+ " cannot be located: " + e);
}
}
/**
* The method based function
*/
private static class MethodFunction extends Function {
/** the method to invoke */
private final Method method;
/** the arity of the method */
private final int arity;
/** the static modifier */
private final boolean isStatic;
/**
* The constructor
*
* @param method the wrapped method
*/
public MethodFunction(Method method) {
this.method = method;
isStatic = Modifier.isStatic(method.getModifiers());
arity = method.getParameterTypes().length + (isStatic ? 0 : 1);
}
@Override
public Object apply(SourceLocation location, List<Object> args) {
assert args.size() == arity;
Object[] a = (isStatic ? args : args.subList(1, arity)).toArray();
Object t = isStatic ? null : args.get(0);
try {
return method.invoke(t, a);
} catch (Exception e) {
throw new EvalException(location, "The method " + method
+ " cannot be invoked: " + e);
}
}
@Override
public int arity() {
return arity;
}
}
}