Added sealed classes to AST

This commit is contained in:
luca9913 2023-07-14 08:52:51 +02:00
parent 1643412f1b
commit c0c46e197f
7 changed files with 235 additions and 210 deletions

View File

@ -85,6 +85,7 @@ import de.dhbwstuttgart.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric;
import de.dhbwstuttgart.syntaxtree.type.TypePlaceholder; import de.dhbwstuttgart.syntaxtree.type.TypePlaceholder;
import de.dhbwstuttgart.syntaxtree.type.Void; import de.dhbwstuttgart.syntaxtree.type.Void;
import de.dhbwstuttgart.typeinference.constraints.GenericsResolver; import de.dhbwstuttgart.typeinference.constraints.GenericsResolver;
import javassist.compiler.SyntaxError;
public class SyntaxTreeGenerator { public class SyntaxTreeGenerator {
private JavaClassRegistry reg; private JavaClassRegistry reg;
@ -219,22 +220,15 @@ public class SyntaxTreeGenerator {
implementedInterfaces.addAll(convert(ctx.typeList(0), generics)); implementedInterfaces.addAll(convert(ctx.typeList(0), generics));
} }
// Ist Bit für 'sealed'-Modifier gesetzt // Ist Bit für 'sealed'-Modifier gesetzt
if ((modifiers & 4096) != 0) { if ((modifiers & 4096) != 0 && !Objects.isNull(ctx.PERMITS())) {
switch (ctx.typeList().size()) { // permitted subtypes sind letzte typeList (siehe Grammatikregel 'classDeclaration')
case 1: { permittedSubtypes.addAll(convert(ctx.typeList(ctx.typeList().size() - 1), generics));
permittedSubtypes.addAll(convert(ctx.typeList(0), generics)); } else {
break; // falls sealed modifier ohne 'permits'-List oder umgekehrt
throw new NotImplementedException("Invalid sealed class declaration");
} }
case 2: { return new ClassOrInterface(modifiers, name, fielddecl, Optional.of(this.generatePseudoConstructor(ctx.identifier().getText(), name, superClass, genericClassParameters, offset)), methods, constructors, genericClassParameters, superClass, isInterface, implementedInterfaces, permittedSubtypes, offset);
permittedSubtypes.addAll(convert(ctx.typeList(1), generics));
break;
}
default: {
break;
}
}
}
return new ClassOrInterface(modifiers, name, fielddecl, Optional.of(this.generatePseudoConstructor(ctx.identifier().getText(), name, superClass, genericClassParameters, offset)), methods, constructors, genericClassParameters, superClass, isInterface, implementedInterfaces, offset);
} }
private de.dhbwstuttgart.syntaxtree.Record convertRecord(RecordDeclarationContext recordDeclaration, int modifiers) { private de.dhbwstuttgart.syntaxtree.Record convertRecord(RecordDeclarationContext recordDeclaration, int modifiers) {
@ -388,7 +382,16 @@ public class SyntaxTreeGenerator {
if (!Objects.isNull(ctx.EXTENDS())) { if (!Objects.isNull(ctx.EXTENDS())) {
extendedInterfaces.addAll(convert(ctx.typeList(0), generics)); extendedInterfaces.addAll(convert(ctx.typeList(0), generics));
} }
return new ClassOrInterface(modifiers, name, fields, Optional.empty(), methods, new ArrayList<>(), genericParams, superClass, true, extendedInterfaces, ctx.getStart()); List<RefType> permittedSubtypes = new ArrayList<>();
// Ist Bit für 'sealed'-Modifier gesetzt
if ((modifiers & 4096) != 0 && !Objects.isNull(ctx.PERMITS())) {
// permitted subtypes sind letzte typeList (siehe Grammatikregel 'classDeclaration')
permittedSubtypes.addAll(convert(ctx.typeList(ctx.typeList().size() - 1), generics));
} else {
// falls sealed modifier ohne 'permits'-List oder umgekehrt
throw new NotImplementedException("Invalid sealed class declaration");
}
return new ClassOrInterface(modifiers, name, fields, Optional.empty(), methods, new ArrayList<>(), genericParams, superClass, true, extendedInterfaces, permittedSubtypes, ctx.getStart());
} }
private GenericDeclarationList createEmptyGenericDeclarationList(Token classNameIdentifier) { private GenericDeclarationList createEmptyGenericDeclarationList(Token classNameIdentifier) {

View File

@ -2,7 +2,6 @@ package de.dhbwstuttgart.syntaxtree;
import de.dhbwstuttgart.parser.SyntaxTreeGenerator.AssignToLocal; import de.dhbwstuttgart.parser.SyntaxTreeGenerator.AssignToLocal;
import de.dhbwstuttgart.syntaxtree.statement.*; import de.dhbwstuttgart.syntaxtree.statement.*;
import de.dhbwstuttgart.syntaxtree.statement.Literal;
import de.dhbwstuttgart.syntaxtree.type.*; import de.dhbwstuttgart.syntaxtree.type.*;
import java.util.Iterator; import java.util.Iterator;
@ -274,4 +273,47 @@ public abstract class AbstractASTWalker implements ASTVisitor {
public void visit(SuperCall superCall) { public void visit(SuperCall superCall) {
this.visit((MethodCall) superCall); this.visit((MethodCall) superCall);
} }
@Override
public void visit(Switch switchStmt) {
switchStmt.getSwitch().accept(this);
switchStmt.getBlocks().stream().forEach((switchBlock) -> {
switchBlock.accept(this);
});
}
@Override
public void visit(SwitchBlock switchBlock) {
switchBlock.getLabels().stream().forEach((label) -> {
label.accept(this);
});
switchBlock.getStatements().stream().forEach((stmt) -> {
stmt.accept(this);
});
}
@Override
public void visit(SwitchLabel switchLabel) {
switchLabel.getExpression().accept(this);
}
@Override
public void visit(Yield aYield) {
aYield.accept(this);
}
@Override
public void visit(Pattern aPattern) {
}
@Override
public void visit(RecordPattern aRecordPattern) {
}
@Override
public void visit(GuardedPattern aGuardedPattern) {
}
} }

View File

@ -35,13 +35,13 @@ public class ClassOrInterface extends SyntaxTreeNode implements TypeScope{
private RefType superClass; private RefType superClass;
protected boolean isInterface; protected boolean isInterface;
private List<RefType> implementedInterfaces; private List<RefType> implementedInterfaces;
private List<RefType> permittedSubtypes;
private List<Constructor> constructors; private List<Constructor> constructors;
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) {
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, Token offset){
super(offset); super(offset);
if(isInterface && !Modifier.isInterface(modifiers))modifiers += Modifier.INTERFACE; if (isInterface && !Modifier.isInterface(modifiers))
modifiers += Modifier.INTERFACE;
this.modifiers = modifiers; this.modifiers = modifiers;
this.name = name; this.name = name;
this.fields = fielddecl; this.fields = fielddecl;
@ -50,12 +50,13 @@ public class ClassOrInterface extends SyntaxTreeNode implements TypeScope{
this.superClass = superClass; this.superClass = superClass;
this.isInterface = isInterface; this.isInterface = isInterface;
this.implementedInterfaces = implementedInterfaces; this.implementedInterfaces = implementedInterfaces;
this.permittedSubtypes = permittedSubtypes;
this.methods = methods; this.methods = methods;
this.constructors = constructors; this.constructors = constructors;
} }
/* erzeugt fuer Fields, Konstruktoren und Methoden neue ArrayList-Objekte /*
* alle anderen Datenobjekte werden nur kopiert. * erzeugt fuer Fields, Konstruktoren und Methoden neue ArrayList-Objekte alle anderen Datenobjekte werden nur kopiert.
*/ */
public ClassOrInterface(ClassOrInterface cl) { public ClassOrInterface(ClassOrInterface cl) {
super(cl.getOffset()); super(cl.getOffset());
@ -104,9 +105,7 @@ public class ClassOrInterface extends SyntaxTreeNode implements TypeScope{
} }
/* /*
public RefType getType() { * public RefType getType() { return generateTypeOfClass(this.getClassName(), this.getGenerics(), this.getOffset()); }
return generateTypeOfClass(this.getClassName(), this.getGenerics(), this.getOffset());
}
*/ */
// TODO: Das hier ist ein Problem. Je nach Kontext wird hier ein anderer Typ benötigt // TODO: Das hier ist ein Problem. Je nach Kontext wird hier ein anderer Typ benötigt
public static RefType generateTypeOfClass(JavaClassName name, GenericDeclarationList genericsOfClass, Token offset) { public static RefType generateTypeOfClass(JavaClassName name, GenericDeclarationList genericsOfClass, Token offset) {
@ -131,9 +130,9 @@ public class ClassOrInterface extends SyntaxTreeNode implements TypeScope{
} }
return new RefType(name, params, new NullToken()); return new RefType(name, params, new NullToken());
} }
/** /**
* Die Superklasse im Kontext dieser ClassOrInterface * Die Superklasse im Kontext dieser ClassOrInterface Das bedeutet, dass generische Variablen als GenericRefTypes dargestellt sind
* Das bedeutet, dass generische Variablen als GenericRefTypes dargestellt sind
*/ */
public RefType getSuperClass() { public RefType getSuperClass() {
return superClass; return superClass;

View File

@ -1,5 +1,6 @@
package de.dhbwstuttgart.syntaxtree; package de.dhbwstuttgart.syntaxtree;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
@ -11,6 +12,6 @@ import de.dhbwstuttgart.syntaxtree.type.RefType;
public class Record extends ClassOrInterface { public class Record extends ClassOrInterface {
public Record(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, Token offset) { public Record(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, Token offset) {
super(modifiers, name, fielddecl, fieldInitializations, methods, constructors, genericClassParameters, superClass, isInterface, implementedInterfaces, offset); super(modifiers, name, fielddecl, fieldInitializations, methods, constructors, genericClassParameters, superClass, isInterface, implementedInterfaces, new ArrayList<>(), offset);
} }
} }

View File

@ -29,9 +29,7 @@ import org.objectweb.asm.signature.SignatureReader;
import org.objectweb.asm.signature.SignatureVisitor; import org.objectweb.asm.signature.SignatureVisitor;
/** /**
* Anmerkung: * Anmerkung: Die ASTFactory Methoden, welche ASTBäume aus java.lang.Class Objekten generieren, können davon ausgehen, dass alle Imports und Typnamen korrekt sind und müssen diese nicht überprüfen.
* Die ASTFactory Methoden, welche ASTBäume aus java.lang.Class Objekten generieren, können davon ausgehen,
* dass alle Imports und Typnamen korrekt sind und müssen diese nicht überprüfen.
*/ */
public class ASTFactory { public class ASTFactory {
@ -132,12 +130,18 @@ public class ASTFactory {
for (Type jreInterface : jreClass.getGenericInterfaces()) { for (Type jreInterface : jreClass.getGenericInterfaces()) {
implementedInterfaces.add((RefType) createType(jreInterface)); implementedInterfaces.add((RefType) createType(jreInterface));
} }
List<RefType> permittedSubtypes = new ArrayList<>();
if (jreClass.isSealed()) {
for (Class subclass : jreClass.getPermittedSubclasses()) {
permittedSubtypes.add((RefType) createType(subclass));
}
}
GenericDeclarationList genericDeclarationList = createGenerics(jreClass.getTypeParameters(), jreClass, null, classSignature); GenericDeclarationList genericDeclarationList = createGenerics(jreClass.getTypeParameters(), jreClass, null, classSignature);
Token offset = new NullToken(); // Braucht keinen Offset, da diese Klasse nicht aus einem Quellcode geparst wurde Token offset = new NullToken(); // Braucht keinen Offset, da diese Klasse nicht aus einem Quellcode geparst wurde
return new ClassOrInterface(modifier, name, felder, Optional.empty() /* eingefuegt PL 2018-11-24 */,methoden, konstruktoren, genericDeclarationList, superClass,isInterface, implementedInterfaces, offset); return new ClassOrInterface(modifier, name, felder, Optional.empty() /* eingefuegt PL 2018-11-24 */, methoden, konstruktoren, genericDeclarationList, superClass, isInterface, implementedInterfaces, permittedSubtypes, offset);
} }
private static Field createField(java.lang.reflect.Field field, JavaClassName jreClass) { private static Field createField(java.lang.reflect.Field field, JavaClassName jreClass) {
@ -156,7 +160,8 @@ public class ASTFactory {
List<FormalParameter> params = new ArrayList<>(); List<FormalParameter> params = new ArrayList<>();
int i = 0; int i = 0;
for (Type jreParam : jreGenericParams) { for (Type jreParam : jreGenericParams) {
if (jreParam == null) continue; if (jreParam == null)
continue;
RefTypeOrTPHOrWildcardOrGeneric paramType = createType(jreParam); RefTypeOrTPHOrWildcardOrGeneric paramType = createType(jreParam);
params.add(new FormalParameter(jreParams[i].getName(), paramType, new NullToken())); params.add(new FormalParameter(jreParams[i].getName(), paramType, new NullToken()));
i++; i++;
@ -189,7 +194,8 @@ public class ASTFactory {
List<FormalParameter> params = new ArrayList<>(); List<FormalParameter> params = new ArrayList<>();
int i = 0; int i = 0;
for (Type jreParam : jreGenericParams) { for (Type jreParam : jreGenericParams) {
if (jreParam == null) continue; if (jreParam == null)
continue;
RefTypeOrTPHOrWildcardOrGeneric paramType = createType(jreParam); RefTypeOrTPHOrWildcardOrGeneric paramType = createType(jreParam);
params.add(new FormalParameter(jreParams[i].getName(), paramType, new NullToken())); params.add(new FormalParameter(jreParams[i].getName(), paramType, new NullToken()));
i++; i++;
@ -217,7 +223,8 @@ public class ASTFactory {
} }
public static GenericDeclarationList createGenerics(String signature) { public static GenericDeclarationList createGenerics(String signature) {
if (signature == null) return new GenericDeclarationList(new ArrayList<>(), new NullToken()); if (signature == null)
return new GenericDeclarationList(new ArrayList<>(), new NullToken());
var gtvs = new ArrayList<GenericTypeVar>(); var gtvs = new ArrayList<GenericTypeVar>();
var signatureVisitor = new SignatureVisitor(Opcodes.ASM7) { var signatureVisitor = new SignatureVisitor(Opcodes.ASM7) {
@ -226,7 +233,8 @@ public class ASTFactory {
final Stack<RefType> classTypes = new Stack<>(); final Stack<RefType> classTypes = new Stack<>();
// All hail the mighty visitor pattern // All hail the mighty visitor pattern
final SignatureVisitor doNothing = new SignatureVisitor(Opcodes.ASM7) {}; final SignatureVisitor doNothing = new SignatureVisitor(Opcodes.ASM7) {
};
char wildcard = '='; char wildcard = '=';
@ -404,48 +412,26 @@ public class ASTFactory {
} }
/* /*
public Constructor createEmptyConstructor(Class parent){ * public Constructor createEmptyConstructor(Class parent){ Block block = new Block(); block.setType(new de.dhbwstuttgart.syntaxtree.type.Void(block, 0)); block.statements.add(new SuperCall(block));
Block block = new Block(); *
block.setType(new de.dhbwstuttgart.syntaxtree.type.Void(block, 0)); * return ASTFactory.createConstructor(parent, new ParameterList(), block); }
block.statements.add(new SuperCall(block)); *
* public static Constructor createConstructor(Class superClass, ParameterList paralist, Block block){ block.parserPostProcessing(superClass);
return ASTFactory.createConstructor(parent, new ParameterList(), block); *
} * Method method = ASTFactory.createMethod("<init>", paralist, block, superClass); method.setType(new de.dhbwstuttgart.syntaxtree.type.Void(block, 0));
*
public static Constructor createConstructor(Class superClass, ParameterList paralist, Block block){ * return new Constructor(method, superClass); }
block.parserPostProcessing(superClass); *
* public static Class createClass(String className, RefType type, Modifiers modifiers, Menge supertypeGenPara, SourceFile parent) { // TODO bytecode createClass //String name, RefType superClass, Modifiers modifiers, Menge<String> supertypeGenPara Class generatedClass = new Class(className, type, modifiers, supertypeGenPara); generatedClass.addField(ASTFactory.createEmptyConstructor(generatedClass));
Method method = ASTFactory.createMethod("<init>", paralist, block, superClass); *
method.setType(new de.dhbwstuttgart.syntaxtree.type.Void(block, 0)); * generatedClass.parserPostProcessing(parent);
*
return new Constructor(method, superClass); * return generatedClass; }
} *
* public static Class createObject(){ return createClass(java.lang.Object.class); }
public static Class createClass(String className, RefType type, Modifiers modifiers, Menge supertypeGenPara, SourceFile parent) { *
// TODO bytecode createClass * public static Class createInterface(String className, RefType superClass, Modifiers modifiers, Menge supertypeGenPara, SourceFile parent){ Class generatedClass = new Class(new JavaClassName(className), new ArrayList<Method>(), new ArrayList<Field>(), modifiers, true, superClass, new ArrayList<RefType>(), new GenericDeclarationList(), -1); generatedClass.parserPostProcessing(parent); return generatedClass; }
//String name, RefType superClass, Modifiers modifiers, Menge<String> supertypeGenPara *
Class generatedClass = new Class(className, type, modifiers, supertypeGenPara); * public static RefType createObjectType(){ return createObjectClass().getType(); }
generatedClass.addField(ASTFactory.createEmptyConstructor(generatedClass));
generatedClass.parserPostProcessing(parent);
return generatedClass;
}
public static Class createObject(){
return createClass(java.lang.Object.class);
}
public static Class createInterface(String className, RefType superClass, Modifiers modifiers,
Menge supertypeGenPara, SourceFile parent){
Class generatedClass = new Class(new JavaClassName(className), new ArrayList<Method>(), new ArrayList<Field>(), modifiers,
true, superClass, new ArrayList<RefType>(), new GenericDeclarationList(), -1);
generatedClass.parserPostProcessing(parent);
return generatedClass;
}
public static RefType createObjectType(){
return createObjectClass().getType();
}
*/ */
} }

View File

@ -17,11 +17,9 @@ public class FamilyOfGenerics {
@Test @Test
public void generateBC() throws Exception { public void generateBC() throws Exception {
/*SourceFile sf = generateAST(); /*
PositionFinder.getPositionOfTPH(sf, null); * SourceFile sf = generateAST(); PositionFinder.getPositionOfTPH(sf, null); TPHExtractor tphExtractor = new TPHExtractor(); List<ResultSet> results = new ArrayList<ResultSet>(); GeneratedGenericsFinder generatedGenericsFinder = new GeneratedGenericsFinder(sf, results);
TPHExtractor tphExtractor = new TPHExtractor(); */
List<ResultSet> results = new ArrayList<ResultSet>();
GeneratedGenericsFinder generatedGenericsFinder = new GeneratedGenericsFinder(sf, results);*/
} }
public static SourceFile generateAST() { public static SourceFile generateAST() {
@ -33,10 +31,7 @@ public class FamilyOfGenerics {
String[] paramNames = { "a" }; String[] paramNames = { "a" };
methods.add(generateMethod("testMethode", paramNames)); methods.add(generateMethod("testMethode", paramNames));
classes.add(new ClassOrInterface(Modifier.PUBLIC, new JavaClassName("Test"), fields, Optional.empty(), methods, classes.add(new ClassOrInterface(Modifier.PUBLIC, new JavaClassName("Test"), fields, Optional.empty(), methods, new ArrayList<>(), generateEmptyGenericDeclList(), new RefType(new JavaClassName("java.lang.Object"), new NullToken()), false, new ArrayList<>(), new ArrayList<>(), new NullToken()));
new ArrayList<>(), generateEmptyGenericDeclList(),
new RefType(new JavaClassName("java.lang.Object"), new NullToken()),
false, new ArrayList<>(), new NullToken()));
return new SourceFile("Test.jav", classes, new HashSet<>()); return new SourceFile("Test.jav", classes, new HashSet<>());
} }
@ -49,8 +44,7 @@ public class FamilyOfGenerics {
} }
ParameterList parameterList = new ParameterList(parameters, new NullToken()); ParameterList parameterList = new ParameterList(parameters, new NullToken());
return new Method(Modifier.PUBLIC, methodName, TypePlaceholder.fresh(new NullToken()), parameterList, return new Method(Modifier.PUBLIC, methodName, TypePlaceholder.fresh(new NullToken()), parameterList, new Block(new ArrayList<>(), new NullToken()), generateEmptyGenericDeclList(), new NullToken());
new Block(new ArrayList<>(), new NullToken()), generateEmptyGenericDeclList(), new NullToken());
} }
public static GenericDeclarationList generateEmptyGenericDeclList() { public static GenericDeclarationList generateEmptyGenericDeclList() {

View File

@ -25,7 +25,7 @@ public class ASTToTypedTargetAST {
@Test @Test
public void emptyClass() { public void emptyClass() {
ClassOrInterface emptyClass = new ClassOrInterface(0, new JavaClassName("EmptyClass"), new ArrayList<>(), java.util.Optional.empty(), new ArrayList<>(), new ArrayList<>(), new GenericDeclarationList(new ArrayList<>(), new NullToken()), new RefType(new JavaClassName("Object"), new NullToken()), false, new ArrayList<>(), new NullToken()); ClassOrInterface emptyClass = new ClassOrInterface(0, new JavaClassName("EmptyClass"), new ArrayList<>(), java.util.Optional.empty(), new ArrayList<>(), new ArrayList<>(), new GenericDeclarationList(new ArrayList<>(), new NullToken()), new RefType(new JavaClassName("Object"), new NullToken()), false, new ArrayList<>(), new ArrayList<>(), new NullToken());
ResultSet emptyResultSet = new ResultSet(new HashSet<>()); ResultSet emptyResultSet = new ResultSet(new HashSet<>());
TargetClass emptyTargetClass = new ASTToTargetAST(List.of(emptyResultSet)).convert(emptyClass); TargetClass emptyTargetClass = new ASTToTargetAST(List.of(emptyResultSet)).convert(emptyClass);
assert emptyTargetClass.getName().equals("EmptyClass"); assert emptyTargetClass.getName().equals("EmptyClass");