Skip to content

fix: Use Python object for Score, handle descriptor correctly, do not copy parent fields #66

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import static ai.timefold.jpyinterpreter.PythonBytecodeToJavaBytecodeTranslator.ARGUMENT_SPEC_INSTANCE_FIELD_NAME;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
Expand Down Expand Up @@ -38,6 +39,7 @@
import ai.timefold.jpyinterpreter.types.BuiltinTypes;
import ai.timefold.jpyinterpreter.types.CPythonBackedPythonLikeObject;
import ai.timefold.jpyinterpreter.types.GeneratedFunctionMethodReference;
import ai.timefold.jpyinterpreter.types.PythonJavaTypeMapping;
import ai.timefold.jpyinterpreter.types.PythonLikeFunction;
import ai.timefold.jpyinterpreter.types.PythonLikeType;
import ai.timefold.jpyinterpreter.types.PythonNone;
Expand Down Expand Up @@ -65,6 +67,7 @@ public class PythonClassTranslator {
public static final String TYPE_FIELD_NAME = "$TYPE";
public static final String CPYTHON_TYPE_FIELD_NAME = "$CPYTHON_TYPE";
private static final String JAVA_METHOD_PREFIX = "$method$";
private static final String PYTHON_JAVA_TYPE_MAPPING_PREFIX = "$pythonJavaTypeMapping";

public record PreparedClassInfo(PythonLikeType type, String className, String classInternalName) {
}
Expand Down Expand Up @@ -205,7 +208,25 @@ public static PythonLikeType translatePythonClass(PythonCompiledClass pythonComp
}
}

for (int i = 0; i < pythonCompiledClass.pythonJavaTypeMappings.size(); i++) {
classWriter.visitField(Modifier.PUBLIC | Modifier.STATIC, PYTHON_JAVA_TYPE_MAPPING_PREFIX + i,
Type.getDescriptor(PythonJavaTypeMapping.class), null, null);
}

Map<String, PythonLikeType> attributeNameToTypeMap = new HashMap<>();
instanceAttributeSet.removeAll(pythonCompiledClass.staticAttributeDescriptorNames);
try {
var parentClass = superClassType.getJavaClass();
while (parentClass != Object.class) {
for (Field field : parentClass.getFields()) {
instanceAttributeSet.remove(field.getName());
}
parentClass = parentClass.getSuperclass();
}
} catch (ClassNotFoundException e) {
throw new IllegalStateException(e);
}

for (String attributeName : instanceAttributeSet) {
var typeHint = pythonCompiledClass.typeAnnotations.getOrDefault(attributeName,
TypeHint.withoutAnnotations(BuiltinTypes.BASE_TYPE));
Expand Down Expand Up @@ -243,8 +264,8 @@ public static PythonLikeType translatePythonClass(PythonCompiledClass pythonComp
}
fieldVisitor.visitEnd();

createJavaGetterSetter(classWriter, preparedClassInfo,
attributeName,
createJavaGetterSetter(classWriter, pythonCompiledClass,
preparedClassInfo, attributeName,
Type.getType(javaFieldTypeDescriptor),
Type.getType(getterTypeDescriptor),
signature,
Expand Down Expand Up @@ -368,6 +389,10 @@ public static PythonLikeType translatePythonClass(PythonCompiledClass pythonComp
generatedClass = (Class<? extends PythonLikeObject>) BuiltinTypes.asmClassLoader.loadClass(className);
generatedClass.getField(TYPE_FIELD_NAME).set(null, pythonLikeType);
generatedClass.getField(CPYTHON_TYPE_FIELD_NAME).set(null, pythonCompiledClass.binaryType);
for (int i = 0; i < pythonCompiledClass.pythonJavaTypeMappings.size(); i++) {
generatedClass.getField(PYTHON_JAVA_TYPE_MAPPING_PREFIX + i)
.set(null, pythonCompiledClass.pythonJavaTypeMappings.get(i));
}
} catch (ClassNotFoundException e) {
throw new IllegalStateException("Impossible State: Unable to load generated class (" +
className + ") despite it being just generated.", e);
Expand Down Expand Up @@ -785,16 +810,31 @@ private static PythonLikeFunction createConstructor(String classInternalName,
}
}

private record MatchedMapping(int index, PythonJavaTypeMapping<?, ?> pythonJavaTypeMapping) {
}

private static void createJavaGetterSetter(ClassWriter classWriter,
PythonCompiledClass pythonCompiledClass,
PreparedClassInfo preparedClassInfo,
String attributeName, Type attributeType, Type getterType,
String signature,
TypeHint typeHint) {
createJavaGetter(classWriter, preparedClassInfo, attributeName, attributeType, getterType, signature, typeHint);
createJavaSetter(classWriter, preparedClassInfo, attributeName, attributeType, getterType, signature, typeHint);
MatchedMapping matchedMapping = null;
for (int i = 0; i < pythonCompiledClass.pythonJavaTypeMappings.size(); i++) {
var mapping = pythonCompiledClass.pythonJavaTypeMappings.get(i);
if (mapping.getPythonType().equals(typeHint.javaGetterType())) {
matchedMapping = new MatchedMapping(i, mapping);
getterType = Type.getType(mapping.getJavaType());
}
}
createJavaGetter(classWriter, preparedClassInfo, matchedMapping, attributeName, attributeType, getterType, signature,
typeHint);
createJavaSetter(classWriter, preparedClassInfo, matchedMapping, attributeName, attributeType, getterType, signature,
typeHint);
}

private static void createJavaGetter(ClassWriter classWriter, PreparedClassInfo preparedClassInfo, String attributeName,
private static void createJavaGetter(ClassWriter classWriter, PreparedClassInfo preparedClassInfo,
MatchedMapping matchedMapping, String attributeName,
Type attributeType, Type getterType, String signature, TypeHint typeHint) {
var getterName = "get" + attributeName.substring(0, 1).toUpperCase() + attributeName.substring(1);
if (signature != null && Objects.equals(attributeType, getterType)) {
Expand Down Expand Up @@ -826,14 +866,30 @@ private static void createJavaGetter(ClassWriter classWriter, PreparedClassInfo
// If branch is not taken, stack is null
}
if (!Objects.equals(attributeType, getterType)) {
if (matchedMapping != null) {
getterVisitor.visitInsn(Opcodes.DUP);
getterVisitor.visitInsn(Opcodes.ACONST_NULL);
Label skipMapping = new Label();
getterVisitor.visitJumpInsn(Opcodes.IF_ACMPEQ, skipMapping);
getterVisitor.visitFieldInsn(Opcodes.GETSTATIC, preparedClassInfo.classInternalName,
PYTHON_JAVA_TYPE_MAPPING_PREFIX + matchedMapping.index,
Type.getDescriptor(PythonJavaTypeMapping.class));
getterVisitor.visitInsn(Opcodes.SWAP);
getterVisitor.visitMethodInsn(Opcodes.INVOKEINTERFACE,
Type.getInternalName(PythonJavaTypeMapping.class), "toJavaObject",
Type.getMethodDescriptor(Type.getType(Object.class), Type.getType(Object.class)),
true);
getterVisitor.visitLabel(skipMapping);
}
getterVisitor.visitTypeInsn(Opcodes.CHECKCAST, getterType.getInternalName());
}
getterVisitor.visitInsn(Opcodes.ARETURN);
getterVisitor.visitMaxs(maxStack, 0);
getterVisitor.visitEnd();
}

private static void createJavaSetter(ClassWriter classWriter, PreparedClassInfo preparedClassInfo, String attributeName,
private static void createJavaSetter(ClassWriter classWriter, PreparedClassInfo preparedClassInfo,
MatchedMapping matchedMapping, String attributeName,
Type attributeType, Type setterType, String signature, TypeHint typeHint) {
var setterName = "set" + attributeName.substring(0, 1).toUpperCase() + attributeName.substring(1);
if (signature != null && Objects.equals(attributeType, setterType)) {
Expand Down Expand Up @@ -861,6 +917,21 @@ private static void createJavaSetter(ClassWriter classWriter, PreparedClassInfo
// If branch is not taken, stack is None
}
if (!Objects.equals(attributeType, setterType)) {
if (matchedMapping != null) {
setterVisitor.visitVarInsn(Opcodes.ALOAD, 1);
setterVisitor.visitInsn(Opcodes.ACONST_NULL);
Label skipMapping = new Label();
setterVisitor.visitJumpInsn(Opcodes.IF_ACMPEQ, skipMapping);
setterVisitor.visitFieldInsn(Opcodes.GETSTATIC, preparedClassInfo.classInternalName,
PYTHON_JAVA_TYPE_MAPPING_PREFIX + matchedMapping.index,
Type.getDescriptor(PythonJavaTypeMapping.class));
setterVisitor.visitInsn(Opcodes.SWAP);
setterVisitor.visitMethodInsn(Opcodes.INVOKEINTERFACE,
Type.getInternalName(PythonJavaTypeMapping.class), "toPythonObject",
Type.getMethodDescriptor(Type.getType(Object.class), Type.getType(Object.class)),
true);
setterVisitor.visitLabel(skipMapping);
}
setterVisitor.visitTypeInsn(Opcodes.CHECKCAST, attributeType.getInternalName());
}
setterVisitor.visitFieldInsn(Opcodes.PUTFIELD, preparedClassInfo.classInternalName,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

import java.util.List;
import java.util.Map;
import java.util.Set;

import ai.timefold.jpyinterpreter.types.PythonJavaTypeMapping;
import ai.timefold.jpyinterpreter.types.PythonLikeType;
import ai.timefold.jpyinterpreter.types.wrappers.CPythonType;
import ai.timefold.jpyinterpreter.types.wrappers.OpaquePythonReference;
Expand Down Expand Up @@ -41,6 +43,11 @@ public class PythonCompiledClass {
*/
public List<Class<?>> javaInterfaces;

/**
* Mapping from Python types to Java types
*/
public List<PythonJavaTypeMapping<?, ?>> pythonJavaTypeMappings;

/**
* The binary type of this PythonCompiledClass;
* typically {@link CPythonType}. Used when methods
Expand All @@ -62,6 +69,11 @@ public class PythonCompiledClass {
*/
public Map<String, OpaquePythonReference> staticAttributeNameToClassInstance;

/**
* Contains static attributes that have get/set descriptors
*/
public Set<String> staticAttributeDescriptorNames;

public String getGeneratedClassBaseName() {
return getGeneratedClassBaseName(module, qualifiedName);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,8 +125,8 @@ public interface PythonLikeObject {
return PythonBoolean.valueOf(!Objects.equals(this, other));
}

default PythonLikeObject $method$__str__() {
return PythonString.valueOf(this.toString());
default PythonString $method$__str__() {
return PythonString.valueOf(this.getClass().getSimpleName() + "@" + System.identityHashCode(this));
}

default PythonLikeObject $method$__repr__() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,4 +49,9 @@ public AbstractPythonLikeObject(PythonLikeType __type__, Map<String, PythonLikeO
public void setAttribute(String attributeName, PythonLikeObject value) {
__dir__.put(attributeName, value);
}

@Override
public String toString() {
return $method$__str__().toString();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ private Ellipsis() {
super(ELLIPSIS_TYPE);
}

@Override
public PythonString $method$__str__() {
return PythonString.valueOf(toString());
}

@Override
public String toString() {
return "NotImplemented";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@ private NotImplemented() {
super(NOT_IMPLEMENTED_TYPE);
}

@Override
public PythonString $method$__str__() {
return PythonString.valueOf(toString());
}

@Override
public String toString() {
return "NotImplemented";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1914,6 +1914,11 @@ public PythonString repr() {
return asString();
}

@Override
public PythonString $method$__str__() {
return PythonString.valueOf(toString());
}

@Override
public String toString() {
StringBuilder out = new StringBuilder(valueBuffer.limit());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1686,6 +1686,11 @@ public PythonString repr() {
return asString();
}

@Override
public PythonString $method$__str__() {
return PythonString.valueOf(toString());
}

@Override
public String toString() {
boolean hasSingleQuotes = false;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package ai.timefold.jpyinterpreter.types;

public interface PythonJavaTypeMapping<PythonType_, JavaType_> {
PythonLikeType getPythonType();

Class<? extends JavaType_> getJavaType();

PythonType_ toPythonObject(JavaType_ javaObject);

JavaType_ toJavaObject(PythonType_ pythonObject);
}
Original file line number Diff line number Diff line change
Expand Up @@ -598,6 +598,11 @@ public List<PythonLikeType> getParentList() {
return PARENT_TYPES;
}

@Override
public PythonString $method$__str__() {
return PythonString.valueOf(toString());
}

@Override
public String toString() {
return "<class " + TYPE_NAME + ">";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@ private PythonNone() {
super(BuiltinTypes.NONE_TYPE);
}

@Override
public PythonString $method$__str__() {
return PythonString.valueOf(toString());
}

@Override
public String toString() {
return "None";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1477,6 +1477,11 @@ public PythonString asString() {
return this;
}

@Override
public PythonString $method$__str__() {
return this;
}

@Override
public String toString() {
return value;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,11 @@ public int hashCode() {
return Objects.hash(delegate);
}

@Override
public PythonString $method$__str__() {
return PythonString.valueOf(toString());
}

@Override
public String toString() {
return delegate.toString();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -558,6 +558,11 @@ public List<T> subList(int i, int i1) {
return delegate.subList(i, i1);
}

@Override
public PythonString $method$__str__() {
return PythonString.valueOf(toString());
}

@Override
public String toString() {
StringBuilder out = new StringBuilder();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import ai.timefold.jpyinterpreter.types.PythonLikeComparable;
import ai.timefold.jpyinterpreter.types.PythonLikeType;
import ai.timefold.jpyinterpreter.types.PythonSlice;
import ai.timefold.jpyinterpreter.types.PythonString;
import ai.timefold.jpyinterpreter.types.errors.TypeError;
import ai.timefold.jpyinterpreter.types.errors.ValueError;
import ai.timefold.jpyinterpreter.types.errors.lookup.IndexError;
Expand Down Expand Up @@ -444,6 +445,11 @@ public int hashCode() {
return PythonInteger.valueOf(hashCode());
}

@Override
public PythonString $method$__str__() {
return PythonString.valueOf(toString());
}

@Override
public String toString() {
return delegate.toString();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -328,8 +328,9 @@ public PythonString isoformat(PythonString formatSpec) {
return PythonString.valueOf(result);
}

public PythonString toPythonString() {
return new PythonString(localTime.toString());
@Override
public PythonString $method$__str__() {
return PythonString.valueOf(toString());
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,11 @@ public PythonBoolean isZero() {
return PythonBoolean.valueOf(duration.isZero());
}

@Override
public PythonString $method$__str__() {
return PythonString.valueOf(toString());
}

@Override
public String toString() {
StringBuilder out = new StringBuilder();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,11 @@ public static PythonBoolean valueOf(boolean result) {
return BuiltinTypes.BOOLEAN_TYPE;
}

@Override
public PythonString $method$__str__() {
return PythonString.valueOf(toString());
}

@Override
public String toString() {
if (this == TRUE) {
Expand Down
Loading