org.python.expose.generate.InstanceMethodExposer Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jython-slim Show documentation
Show all versions of jython-slim Show documentation
Jython is an implementation of the high-level, dynamic, object-oriented
language Python written in 100% Pure Java, and seamlessly integrated with
the Java platform. It thus allows you to run Python on any Java platform.
package org.python.expose.generate;
import org.objectweb.asm.Label;
import org.objectweb.asm.Type;
import org.python.core.PyBuiltinMethod;
import org.python.core.PyBuiltinMethodNarrow;
import org.python.expose.ExposedMethod;
import org.python.expose.MethodType;
/**
* Generates a class to call a given method with the {@link ExposedMethod} annotation as a method on
* a builtin Python type.
*/
public class InstanceMethodExposer extends MethodExposer {
MethodType type;
public InstanceMethodExposer(Type onType,
int access,
String methodName,
String desc,
String typeName) {
this(onType,
access,
methodName,
desc,
typeName,
new String[0],
new String[0],
MethodType.DEFAULT,
"");
}
public InstanceMethodExposer(Type onType,
int access,
String methodName,
String desc,
String typeName,
String[] asNames,
String[] defaults,
MethodType type,
String doc) {
super(onType,
methodName,
Type.getArgumentTypes(desc),
Type.getReturnType(desc),
typeName,
asNames,
defaults,
isWide(desc) ? PyBuiltinMethod.class : PyBuiltinMethodNarrow.class,
doc);
if ((access & ACC_STATIC) != 0) {
throwInvalid("@ExposedMethod can't be applied to static methods");
}
if (isWide(args)) {
if (defaults.length > 0) {
throwInvalid("Can't have defaults on a method that takes PyObject[], String[]");
}
}
this.type = type;
}
protected void checkSelf() {
mv.visitTypeInsn(CHECKCAST, onType.getInternalName());
}
protected void makeCall() {
// Actually call the exposed method
call(onType, methodName, returnType, args);
if (type == MethodType.BINARY) {
checkBinaryResult();
} else if (type == MethodType.CMP) {
checkCmpResult();
}
}
/** Throw NotImplemented if a binary method returned null. */
private void checkBinaryResult() {
// If this is a binary method,
mv.visitInsn(DUP);
Label regularReturn = new Label();
mv.visitJumpInsn(IFNONNULL, regularReturn);
getStatic(PY, "NotImplemented", PYOBJ);
mv.visitInsn(ARETURN);
mv.visitLabel(regularReturn);
}
/** Throw a type error if a cmp method returned -2. */
private void checkCmpResult() {
mv.visitInsn(DUP);
mv.visitIntInsn(BIPUSH, -2);
Label regularReturn = new Label();
mv.visitJumpInsn(IF_ICMPNE, regularReturn);
// tediously build an error message based on the type name
instantiate(STRING_BUILDER, new Instantiator(STRING) {
public void pushArgs() {
mv.visitLdcInsn(typeName + ".__cmp__(x,y) requires y to be '" + typeName
+ "', not a '");
}
});
mv.visitVarInsn(ALOAD, !needsThreadState(args) ? 1 : 2);
call(PYOBJ, "getType", PYTYPE);
call(PYTYPE, "fastGetName", STRING);
call(STRING_BUILDER, "append", STRING_BUILDER, STRING);
mv.visitLdcInsn("'");
call(STRING_BUILDER, "append", STRING_BUILDER, STRING);
call(STRING_BUILDER, "toString", STRING);
// throw a type error with our excellent message since this was of the wrong type.
callStatic(PY, "TypeError", PYEXCEPTION, STRING);
mv.visitInsn(ATHROW);
mv.visitLabel(regularReturn);
}
private static boolean isWide(String methDescriptor) {
return isWide(Type.getArgumentTypes(methDescriptor));
}
}