forked from JavaTX/JavaCompilerCore
Add interfaces
This commit is contained in:
parent
628f1631e8
commit
892ba5fff0
33
resources/bytecode/javFiles/Interfaces.jav
Normal file
33
resources/bytecode/javFiles/Interfaces.jav
Normal file
@ -0,0 +1,33 @@
|
||||
import java.lang.Integer;
|
||||
|
||||
interface A {
|
||||
void method1();
|
||||
default method2() {
|
||||
}
|
||||
}
|
||||
|
||||
interface B {
|
||||
void method3();
|
||||
}
|
||||
|
||||
interface C {
|
||||
Integer myInt();
|
||||
}
|
||||
|
||||
class ClassX implements A {
|
||||
}
|
||||
|
||||
record ClassY(Integer myInt) implements C {}
|
||||
|
||||
public class Interfaces implements A, B {
|
||||
public void method1() {
|
||||
}
|
||||
public void method3() {
|
||||
var intf = new Interfaces();
|
||||
intf = new ClassX();
|
||||
intf.method1();
|
||||
|
||||
C c = new ClassY(10);
|
||||
c.myInt();
|
||||
}
|
||||
}
|
@ -11,6 +11,7 @@ import de.dhbwstuttgart.target.tree.type.*;
|
||||
import org.objectweb.asm.*;
|
||||
|
||||
import java.lang.invoke.*;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.*;
|
||||
|
||||
import static org.objectweb.asm.Opcodes.*;
|
||||
@ -1345,12 +1346,17 @@ public class Codegen {
|
||||
}
|
||||
|
||||
private void generateMethod(TargetMethod method) {
|
||||
var access = method.access() | ACC_PUBLIC;
|
||||
if (method.block() == null)
|
||||
access |= ACC_ABSTRACT;
|
||||
|
||||
// TODO The older codegen has set ACC_PUBLIC for all methods, good for testing but bad for everything else
|
||||
MethodVisitor mv = cw.visitMethod(method.access() | ACC_PUBLIC, method.name(), method.getDescriptor(), method.getSignature(), null);
|
||||
MethodVisitor mv = cw.visitMethod(access, method.name(), method.getDescriptor(), method.getSignature(), null);
|
||||
if (method.txSignature() != null) {
|
||||
mv.visitAttribute(new JavaTXSignatureAttribute(method.getTXSignature()));
|
||||
}
|
||||
|
||||
if (method.block() != null) {
|
||||
mv.visitCode();
|
||||
var state = new State(method.signature().returnType(), mv, method.isStatic() ? 0 : 1);
|
||||
for (var param : method.signature().parameters()) {
|
||||
@ -1360,30 +1366,41 @@ public class Codegen {
|
||||
if (method.signature().returnType() == null)
|
||||
mv.visitInsn(RETURN);
|
||||
mv.visitMaxs(0, 0);
|
||||
}
|
||||
mv.visitEnd();
|
||||
}
|
||||
|
||||
private static String generateSignature(TargetStructure clazz, Set<TargetGeneric> generics) {
|
||||
String ret = "";
|
||||
if (generics.size() > 0) {
|
||||
if (!generics.isEmpty()) {
|
||||
ret += "<";
|
||||
for (var generic : generics) {
|
||||
ret += generic.name() + ":" + generic.bound().toDescriptor();
|
||||
}
|
||||
ret += ">";
|
||||
}
|
||||
if (clazz.superType() != null)
|
||||
ret += clazz.superType().toDescriptor();
|
||||
for (var intf : clazz.implementingInterfaces()) {
|
||||
ret += intf.toSignature();
|
||||
}
|
||||
|
||||
return ret;
|
||||
return ret.isEmpty() ? null : ret;
|
||||
}
|
||||
|
||||
public byte[] generate() {
|
||||
var access = clazz.modifiers();
|
||||
if ((access & ACC_PRIVATE) == 0 && (access & ACC_PROTECTED) == 0) // TODO Implement access modifiers properly
|
||||
access |= ACC_PUBLIC;
|
||||
if (!(clazz instanceof TargetInterface))
|
||||
access |= ACC_SUPER;
|
||||
|
||||
cw.visit(V1_8, access | ACC_SUPER, clazz.qualifiedName().toString().replaceAll("\\.", "/"), generateSignature(clazz, clazz.generics()), clazz.superType() != null ? clazz.superType().getInternalName() : "java/lang/Object", clazz.implementingInterfaces().stream().map(TargetType::toSignature).toArray(String[]::new));
|
||||
if (clazz.txGenerics() != null)
|
||||
var signature = generateSignature(clazz, clazz.generics());
|
||||
var interfaces = clazz.implementingInterfaces().stream().map(TargetType::getInternalName).toArray(String[]::new);
|
||||
var superType = clazz.superType() != null ? clazz.superType().getInternalName() : "java/lang/Object";
|
||||
|
||||
cw.visit(V1_8, access, clazz.qualifiedName().toString().replaceAll("\\.", "/"), signature, superType, interfaces);
|
||||
if (clazz.txGenerics() != null && signature != null)
|
||||
cw.visitAttribute(new JavaTXSignatureAttribute(generateSignature(clazz, clazz.txGenerics())));
|
||||
|
||||
clazz.fields().forEach(this::generateField);
|
||||
|
@ -40,8 +40,9 @@ public class ClassOrInterface extends SyntaxTreeNode implements TypeScope {
|
||||
|
||||
public ClassOrInterface(int modifiers, JavaClassName name, List<Field> fielddecl, Optional<Constructor> fieldInitializations, List<Method> methods, List<Constructor> constructors, GenericDeclarationList genericClassParameters, RefType superClass, Boolean isInterface, List<RefType> implementedInterfaces, List<RefType> permittedSubtypes, Token offset) {
|
||||
super(offset);
|
||||
if (isInterface && !Modifier.isInterface(modifiers))
|
||||
modifiers += Modifier.INTERFACE;
|
||||
if (isInterface) {
|
||||
modifiers |= Modifier.INTERFACE | Modifier.ABSTRACT;
|
||||
}
|
||||
this.modifiers = modifiers;
|
||||
this.name = name;
|
||||
this.fields = fielddecl;
|
||||
@ -72,6 +73,10 @@ public class ClassOrInterface extends SyntaxTreeNode implements TypeScope {
|
||||
this.constructors = new ArrayList<>(cl.constructors);
|
||||
}
|
||||
|
||||
public boolean isInterface() {
|
||||
return (Modifier.INTERFACE & this.getModifiers()) != 0;
|
||||
}
|
||||
|
||||
// Gets if it is added
|
||||
public Boolean areMethodsAdded() {
|
||||
return methodAdded;
|
||||
|
@ -113,7 +113,7 @@ public class OutputGenerator implements ASTVisitor {
|
||||
|
||||
@Override
|
||||
public void visit(ClassOrInterface classOrInterface) {
|
||||
if ((Modifier.INTERFACE & classOrInterface.getModifiers()) == 1) {
|
||||
if (classOrInterface.isInterface()) {
|
||||
out.append("interface ");
|
||||
} else {
|
||||
out.append("class ");
|
||||
|
@ -146,6 +146,8 @@ public class ASTToTargetAST {
|
||||
|
||||
if (input instanceof Record)
|
||||
return new TargetRecord(input.getModifiers(), input.getClassName(), javaGenerics, txGenerics, superInterfaces, constructors, fields, methods);
|
||||
else if (input.isInterface())
|
||||
return new TargetInterface(input.getModifiers(), input.getClassName(), javaGenerics, txGenerics, methods, superInterfaces);
|
||||
else return new TargetClass(input.getModifiers(), input.getClassName(), convert(input.getSuperClass(), generics.javaGenerics), javaGenerics, txGenerics, superInterfaces, constructors, fields, methods);
|
||||
}
|
||||
|
||||
@ -356,6 +358,7 @@ public class ASTToTargetAST {
|
||||
}
|
||||
|
||||
protected TargetBlock convert(Block block) {
|
||||
if (block == null) return null;
|
||||
return new TargetBlock(block.statements.stream().map(this::convert).toList());
|
||||
}
|
||||
|
||||
|
@ -262,6 +262,7 @@ public abstract class GenerateGenerics {
|
||||
}
|
||||
}
|
||||
|
||||
if (method.block != null)
|
||||
method.block.accept(new TracingStatementVisitor() {
|
||||
|
||||
private RefTypeOrTPHOrWildcardOrGeneric superType = new de.dhbwstuttgart.syntaxtree.type.Void(new NullToken());
|
||||
@ -493,6 +494,7 @@ public abstract class GenerateGenerics {
|
||||
typeVariables.addAll(findTypeVariables(arg.getType()));
|
||||
}
|
||||
|
||||
if (method.block != null)
|
||||
method.block.accept(new TracingStatementVisitor() {
|
||||
@Override
|
||||
public void visit(LocalVarDecl localVarDecl) {
|
||||
|
@ -1,6 +1,7 @@
|
||||
package de.dhbwstuttgart.target.tree;
|
||||
|
||||
import de.dhbwstuttgart.parser.scope.JavaClassName;
|
||||
import de.dhbwstuttgart.target.tree.expression.TargetBlock;
|
||||
import de.dhbwstuttgart.target.tree.type.TargetRefType;
|
||||
import de.dhbwstuttgart.target.tree.type.TargetType;
|
||||
|
||||
|
@ -1,6 +1,24 @@
|
||||
package de.dhbwstuttgart.target.tree;
|
||||
|
||||
import java.util.List;
|
||||
import de.dhbwstuttgart.parser.scope.JavaClassName;
|
||||
import de.dhbwstuttgart.target.tree.type.TargetType;
|
||||
|
||||
public record TargetInterface(String name, List<TargetMethod> methods, List<TargetInterface> extendedInterfaces) {
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public record TargetInterface(int modifiers, JavaClassName qualifiedName, Set<TargetGeneric> generics, Set<TargetGeneric> txGenerics, List<TargetMethod> methods, List<TargetType> implementingInterfaces) implements TargetStructure {
|
||||
@Override
|
||||
public TargetType superType() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TargetConstructor> constructors() {
|
||||
return List.of();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TargetField> fields() {
|
||||
return List.of();
|
||||
}
|
||||
}
|
||||
|
@ -10,8 +10,6 @@ import java.util.Set;
|
||||
public record TargetRecord(int modifiers, JavaClassName qualifiedName, Set<TargetGeneric> generics, Set<TargetGeneric> txGenerics, List<TargetType> implementingInterfaces, List<TargetConstructor> constructors, List<TargetField> fields, List<TargetMethod> methods) implements TargetStructure {
|
||||
|
||||
public static final TargetType RECORD = new TargetRefType("java.lang.Record");
|
||||
|
||||
@Override
|
||||
public TargetType superType() {
|
||||
return RECORD;
|
||||
}
|
||||
|
@ -713,4 +713,12 @@ public class TestComplete {
|
||||
assertEquals(m1.invoke(instance, pt), 30);
|
||||
assertEquals(m2.invoke(instance, 10), 10);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInterfaces() throws Exception {
|
||||
var classFiles = generateClassFiles(new ByteArrayClassLoader(), "Interfaces.jav");
|
||||
var clazz = classFiles.get("Interfaces");
|
||||
var instance = clazz.getDeclaredConstructor().newInstance();
|
||||
System.out.println(Arrays.toString(clazz.getInterfaces()));
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user