Skip to content

Commit 4e2466a

Browse files
committed
Complete and utter chaos
1 parent 4f101f8 commit 4e2466a

32 files changed

+1627
-205
lines changed

compiler/src/main/java/dev/ultreon/pythonc/AbstractContext.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ public void push(Type type) {
2020

2121
@Override
2222
public Type pop() {
23-
if (stack.isEmpty()) throw new RuntimeException("Stack is empty");
23+
if (stack.isEmpty())
24+
throw new RuntimeException("Stack is empty");
2425
Type pop = stack.pop();
2526
if (pop.equals(Type.LONG_TYPE) || pop.equals(Type.DOUBLE_TYPE)) stack.pop();
2627
return pop;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package dev.ultreon.pythonc;
2+
3+
import java.lang.reflect.Method;
4+
import java.util.ArrayList;
5+
import java.util.List;
6+
7+
public class ClassUtils {
8+
public static boolean isPrimitive(Class<?> clazz) {
9+
return clazz.isPrimitive();
10+
}
11+
12+
public static Method[] getMethodsByName(Class<?> type, String name) {
13+
try {
14+
List<Method> methods = new ArrayList<>();
15+
for (Method method : type.getDeclaredMethods()) {
16+
if (method.getName().equals(name)) {
17+
methods.add(method);
18+
}
19+
}
20+
for (Method method : type.getMethods()) {
21+
if (method.getName().equals(name)) {
22+
if (methods.contains(method)) continue;
23+
methods.add(method);
24+
}
25+
}
26+
27+
return methods.toArray(Method[]::new);
28+
} catch (SecurityException e) {
29+
throw new RuntimeException(e);
30+
}
31+
}
32+
}

compiler/src/main/java/dev/ultreon/pythonc/FuncCall.java

+170-73
Large diffs are not rendered by default.

compiler/src/main/java/dev/ultreon/pythonc/ImportedField.java

+18-3
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,7 @@
44
import org.objectweb.asm.Opcodes;
55
import org.objectweb.asm.Type;
66

7-
import static org.objectweb.asm.Opcodes.GETSTATIC;
8-
9-
record ImportedField(String name, Type type, String owner, int lineNo) implements Symbol {
7+
record ImportedField(String name, Type type, String owner, int lineNo) implements JvmClassMember {
108
@Override
119
public Object preload(MethodVisitor mv, PythonCompiler compiler, boolean boxed) {
1210
return null;
@@ -79,4 +77,21 @@ public void set(MethodVisitor mv, PythonCompiler compiler, PyExpr visit) {
7977
mv.visitFieldInsn(Opcodes.PUTFIELD, owner, name, type.getDescriptor());
8078
}
8179
}
80+
81+
@Override
82+
public JvmClass ownerClass(PythonCompiler compiler) {
83+
boolean load = PythonCompiler.classCache.load(compiler, Type.getObjectType(owner));
84+
if (!load) {
85+
throw new RuntimeException("Inherited class from " + owner + " not found: " + owner);
86+
}
87+
return PythonCompiler.classCache.get(Type.getObjectType(owner));
88+
}
89+
90+
public JvmClass typeClass(PythonCompiler compiler) {
91+
boolean load = PythonCompiler.classCache.load(compiler, type);
92+
if (!load) {
93+
throw new RuntimeException("Inherited class from " + type + " not found: " + type);
94+
}
95+
return PythonCompiler.classCache.get(type);
96+
}
8297
}

compiler/src/main/java/dev/ultreon/pythonc/JClass.java

+127-10
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,29 @@
11
package dev.ultreon.pythonc;
22

3+
import org.jetbrains.annotations.NotNull;
4+
import org.jetbrains.annotations.Nullable;
35
import org.objectweb.asm.MethodVisitor;
46
import org.objectweb.asm.Type;
57

8+
import java.lang.reflect.Constructor;
9+
import java.lang.reflect.Field;
10+
import java.lang.reflect.Method;
611
import java.lang.reflect.Modifier;
7-
import java.util.Objects;
12+
import java.util.*;
813

914
final class JClass implements JvmClass {
1015
private final String className;
1116
private final Type asmType;
1217
private final Class<?> type;
18+
private String alias;
19+
private final HashMap<String, JvmField> fields = new HashMap<>();
20+
private final Map<String, List<JvmFunction>> functions = new HashMap<>();
1321

14-
JClass(String className) {
22+
JClass(String className, Class<?> type) {
1523
this.className = className;
1624
this.asmType = Type.getObjectType(className.replace(".", "/"));
17-
try {
18-
this.type = Class.forName(className.replace("/", "."), false, getClass().getClassLoader());
19-
} catch (ClassNotFoundException e) {
20-
throw new CompilerException("JVM class not found: " + className);
21-
}
25+
this.alias = alias;
26+
this.type = type;
2227
}
2328

2429
@Override
@@ -85,8 +90,120 @@ public boolean isEnum() {
8590
}
8691

8792
@Override
88-
public boolean doesInherit(Class<?> type) {
89-
return type.isAssignableFrom(this.type);
93+
public boolean doesInherit(PythonCompiler compiler, Type type) {
94+
JvmClass jvmClass = PythonCompiler.classCache.get(type);
95+
if (jvmClass instanceof JClass jClass) {
96+
return jClass.type.isAssignableFrom(this.type);
97+
}
98+
return false;
99+
}
100+
101+
@Override
102+
public JvmFunction constructor(PythonCompiler compiler, Type[] paramTypes) {
103+
Method method;
104+
Constructor<?>[] constructors = type.getConstructors();
105+
JvmClass[] ourParamTypes = new JvmClass[paramTypes.length];
106+
for (int i = 0, paramTypesLength = paramTypes.length; i < paramTypesLength; i++) {
107+
Type paramType = paramTypes[i];
108+
if (!(PythonCompiler.classCache.load(compiler, paramType)))
109+
throw new CompilerException("Class '" + paramType.getClassName() + "' not found (" + compiler.getLocation(this) + ")");
110+
ourParamTypes[i] = PythonCompiler.classCache.get(paramType);
111+
}
112+
113+
Constructor<?> theConstructor;
114+
methodLoop:
115+
for (Constructor<?> constructor1 : constructors) {
116+
@NotNull Class<?>[] parameterTypes = constructor1.getParameterTypes();
117+
for (int i = 0, parameterTypesLength = parameterTypes.length; i < parameterTypesLength; i++) {
118+
Class<?> theParamType = parameterTypes[i];
119+
if (!(PythonCompiler.classCache.load(compiler, Type.getType(theParamType))))
120+
throw new CompilerException("Class '" + theParamType.getName() + "' not found (" + compiler.getLocation(this) + ")");
121+
122+
if (i > ourParamTypes.length - 1) {
123+
continue methodLoop;
124+
}
125+
if (!ourParamTypes[i].doesInherit(compiler, Type.getType(theParamType))) {
126+
continue methodLoop;
127+
}
128+
}
129+
130+
if (ourParamTypes.length != parameterTypes.length) {
131+
continue;
132+
}
133+
134+
JConstructor jFunction = new JConstructor("__init__", constructor1, 0, 0);
135+
this.functions.computeIfAbsent("__init__", k -> new ArrayList<>()).add(jFunction);
136+
return jFunction;
137+
}
138+
139+
throw new CompilerException("Constructor not found (" + compiler.getLocation(this) + ")");
140+
}
141+
142+
@Override
143+
public @Nullable JvmFunction function(PythonCompiler compiler, String name, Type[] paramTypes) {
144+
Method method;
145+
Method[] methodsByName = ClassUtils.getMethodsByName(type, name);
146+
JvmClass[] ourParamTypes = new JvmClass[paramTypes.length];
147+
for (int i = 0, paramTypesLength = paramTypes.length; i < paramTypesLength; i++) {
148+
Type paramType = paramTypes[i];
149+
if (!(PythonCompiler.classCache.load(compiler, paramType)))
150+
throw new CompilerException("Class '" + paramType.getClassName() + "' not found (" + compiler.getLocation(this) + ")");
151+
ourParamTypes[i] = PythonCompiler.classCache.get(paramType);
152+
}
153+
154+
Method theMethod;
155+
methodLoop:
156+
for (Method method1 : methodsByName) {
157+
@NotNull Class<?>[] parameterTypes = method1.getParameterTypes();
158+
for (int i = 0, parameterTypesLength = parameterTypes.length; i < parameterTypesLength; i++) {
159+
Class<?> theParamType = parameterTypes[i];
160+
if (!(PythonCompiler.classCache.load(compiler, Type.getType(theParamType))))
161+
throw new CompilerException("Class '" + theParamType.getName() + "' not found (" + compiler.getLocation(this) + ")");
162+
163+
if (!ourParamTypes[i].doesInherit(compiler, Type.getType(theParamType))) {
164+
continue methodLoop;
165+
}
166+
}
167+
168+
JFunction jFunction = new JFunction(name, method1, 0, 0);
169+
this.functions.computeIfAbsent(name, k -> new ArrayList<>()).add(jFunction);
170+
return jFunction;
171+
}
172+
173+
throw new CompilerException("Method '" + name + "' not found (" + compiler.getLocation(this) + ")");
174+
}
175+
176+
@Override
177+
public boolean isPrimitive() {
178+
return type.isPrimitive();
179+
}
180+
181+
@Override
182+
public @Nullable JvmField field(PythonCompiler compiler, String name) {
183+
Field field;
184+
try {
185+
field = this.type.getField(name);
186+
} catch (NoSuchFieldException e) {
187+
return null;
188+
}
189+
Class<?> type1 = field.getType();
190+
if (Modifier.isStatic(field.getModifiers())) {
191+
if (type1.isPrimitive()) {
192+
Type asmType = Type.getType(type1);
193+
Field finalField = field;
194+
return fields.computeIfAbsent(name, k -> new JField(this, finalField, name, asmType));
195+
}
196+
Field finalField = field;
197+
return fields.computeIfAbsent(name, k -> new JField(this, finalField, name, Type.getType(type1)));
198+
}
199+
if (type1.isPrimitive()) {
200+
Type asmType = Type.getType(type1);
201+
Field finalField1 = field;
202+
return fields.computeIfAbsent(name, k -> new JField(this, finalField1, name, asmType));
203+
} else {
204+
Field finalField2 = field;
205+
return fields.computeIfAbsent(name, k -> new JField(this, finalField2, name, Type.getType(type1)));
206+
}
90207
}
91208

92209
public String className() {
@@ -109,7 +226,7 @@ public int hashCode() {
109226
@Override
110227
public String toString() {
111228
return "JClass[" +
112-
"className=" + className + ']';
229+
"className=" + className + ']';
113230
}
114231

115232
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
package dev.ultreon.pythonc;
2+
3+
import org.objectweb.asm.MethodVisitor;
4+
import org.objectweb.asm.Type;
5+
6+
import java.lang.reflect.Constructor;
7+
import java.lang.reflect.Method;
8+
import java.lang.reflect.Modifier;
9+
10+
import static org.objectweb.asm.Opcodes.*;
11+
12+
public class JConstructor implements JvmFunction, JvmConstructor {
13+
public String name;
14+
public Constructor<?> constructor;
15+
public Class<?> owner;
16+
public Class<?>[] paramTypes;
17+
private JvmClass ownerClass;
18+
private JvmClass[] paramClasses;
19+
private JvmClass returnClass;
20+
private Type[] paramTypesAsm;
21+
private final int lineNo;
22+
private final int columnNo;
23+
24+
public JConstructor(String name, Constructor<?> constructor, int lineNo, int columnNo) {
25+
super();
26+
this.name = name;
27+
this.constructor = constructor;
28+
this.lineNo = lineNo;
29+
this.columnNo = columnNo;
30+
this.owner = constructor.getDeclaringClass();
31+
this.paramTypes = constructor.getParameterTypes();
32+
}
33+
34+
@Override
35+
public void invoke(Object callArgs, Runnable paramInit) {
36+
throw new AssertionError("DEBUG");
37+
}
38+
39+
@Override
40+
public Type returnType(PythonCompiler compiler) {
41+
return Type.getType(owner);
42+
}
43+
44+
@Override
45+
public JvmClass returnClass(PythonCompiler compiler) {
46+
if (!PythonCompiler.classCache.load(compiler, owner)) {
47+
throw new CompilerException("Class '" + owner.getName() + "' not found (" + compiler.getLocation(this) + ")");
48+
}
49+
return PythonCompiler.classCache.get(owner);
50+
}
51+
52+
@Override
53+
public Type[] parameterTypes(PythonCompiler compiler) {
54+
if (this.paramTypesAsm != null) return this.paramTypesAsm;
55+
Type[] types = new Type[paramTypes.length];
56+
for (int i = 0; i < paramTypes.length; i++) {
57+
types[i] = Type.getType(paramTypes[i]);
58+
}
59+
return this.paramTypesAsm = types;
60+
}
61+
62+
@Override
63+
public JvmClass[] parameterClasses(PythonCompiler compiler) {
64+
if (this.paramClasses != null) return this.paramClasses;
65+
this.paramClasses = new JvmClass[paramTypes.length];
66+
for (int i = 0; i < paramTypes.length; i++) {
67+
if (!PythonCompiler.classCache.load(compiler, paramTypes[i]))
68+
throw new CompilerException("Class '" + paramTypes[i].getName() + "' not found (" + compiler.getLocation(this) + ")");
69+
this.paramClasses[i] = PythonCompiler.classCache.get(paramTypes[i]);
70+
}
71+
return this.paramClasses;
72+
}
73+
74+
@Override
75+
public Object preload(MethodVisitor mv, PythonCompiler compiler, boolean boxed) {
76+
return null;
77+
}
78+
79+
@Override
80+
public void load(MethodVisitor mv, PythonCompiler compiler, Object preloaded, boolean boxed) {
81+
throw new UnsupportedOperationException(PythonCompiler.E_NOT_ALLOWED);
82+
}
83+
84+
public void write(MethodVisitor mv, PythonCompiler compiler, Runnable paramInit) {
85+
Type methodType = Type.getMethodType(Type.VOID_TYPE, parameterTypes(compiler));
86+
compiler.writer.newInstance(owner(compiler).type(compiler).getInternalName(), name, methodType.getDescriptor(), false, paramInit);
87+
}
88+
89+
@Override
90+
public int lineNo() {
91+
return lineNo;
92+
}
93+
94+
@Override
95+
public int columnNo() {
96+
return columnNo;
97+
}
98+
99+
@Override
100+
public String name() {
101+
return name;
102+
}
103+
104+
@Override
105+
public Type type(PythonCompiler compiler) {
106+
return returnType(compiler);
107+
}
108+
109+
@Override
110+
public void set(MethodVisitor mv, PythonCompiler compiler, PyExpr visit) {
111+
throw new CompilerException("Cannot set non-python JVM function " + compiler.getLocation(this));
112+
}
113+
114+
@Override
115+
public JvmClass owner(PythonCompiler compiler) {
116+
if (this.ownerClass != null) return this.ownerClass;
117+
if (!PythonCompiler.classCache.load(compiler, owner))
118+
throw new CompilerException("Class '" + owner.getName() + "' not found (" + compiler.getLocation(this) + ")");
119+
this.ownerClass = PythonCompiler.classCache.get(owner);
120+
return this.ownerClass;
121+
}
122+
}

0 commit comments

Comments
 (0)