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.Void;
import de.dhbwstuttgart.typeinference.constraints.GenericsResolver;
import javassist.compiler.SyntaxError;
public class SyntaxTreeGenerator {
private JavaClassRegistry reg;
@ -219,22 +220,15 @@ public class SyntaxTreeGenerator {
implementedInterfaces.addAll(convert(ctx.typeList(0), generics));
}
// Ist Bit für 'sealed'-Modifier gesetzt
if ((modifiers & 4096) != 0) {
switch (ctx.typeList().size()) {
case 1: {
permittedSubtypes.addAll(convert(ctx.typeList(0), generics));
break;
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");
}
case 2: {
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);
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);
}
private de.dhbwstuttgart.syntaxtree.Record convertRecord(RecordDeclarationContext recordDeclaration, int modifiers) {
@ -388,7 +382,16 @@ public class SyntaxTreeGenerator {
if (!Objects.isNull(ctx.EXTENDS())) {
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) {

View File

@ -2,7 +2,6 @@ package de.dhbwstuttgart.syntaxtree;
import de.dhbwstuttgart.parser.SyntaxTreeGenerator.AssignToLocal;
import de.dhbwstuttgart.syntaxtree.statement.*;
import de.dhbwstuttgart.syntaxtree.statement.Literal;
import de.dhbwstuttgart.syntaxtree.type.*;
import java.util.Iterator;
@ -274,4 +273,47 @@ public abstract class AbstractASTWalker implements ASTVisitor {
public void visit(SuperCall 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;
protected boolean isInterface;
private List<RefType> implementedInterfaces;
private List<RefType> permittedSubtypes;
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, 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, List<RefType> permittedSubtypes, Token offset) {
super(offset);
if(isInterface && !Modifier.isInterface(modifiers))modifiers += Modifier.INTERFACE;
if (isInterface && !Modifier.isInterface(modifiers))
modifiers += Modifier.INTERFACE;
this.modifiers = modifiers;
this.name = name;
this.fields = fielddecl;
@ -50,12 +50,13 @@ public class ClassOrInterface extends SyntaxTreeNode implements TypeScope{
this.superClass = superClass;
this.isInterface = isInterface;
this.implementedInterfaces = implementedInterfaces;
this.permittedSubtypes = permittedSubtypes;
this.methods = methods;
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) {
super(cl.getOffset());
@ -104,9 +105,7 @@ public class ClassOrInterface extends SyntaxTreeNode implements TypeScope{
}
/*
public RefType getType() {
return generateTypeOfClass(this.getClassName(), this.getGenerics(), this.getOffset());
}
* public RefType getType() { return generateTypeOfClass(this.getClassName(), this.getGenerics(), this.getOffset()); }
*/
// 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) {
@ -131,9 +130,9 @@ public class ClassOrInterface extends SyntaxTreeNode implements TypeScope{
}
return new RefType(name, params, new NullToken());
}
/**
* Die Superklasse im Kontext dieser ClassOrInterface
* Das bedeutet, dass generische Variablen als GenericRefTypes dargestellt sind
* Die Superklasse im Kontext dieser ClassOrInterface Das bedeutet, dass generische Variablen als GenericRefTypes dargestellt sind
*/
public RefType getSuperClass() {
return superClass;

View File

@ -1,5 +1,6 @@
package de.dhbwstuttgart.syntaxtree;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
@ -11,6 +12,6 @@ import de.dhbwstuttgart.syntaxtree.type.RefType;
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) {
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;
/**
* 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.
* 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.
*/
public class ASTFactory {
@ -132,12 +130,18 @@ public class ASTFactory {
for (Type jreInterface : jreClass.getGenericInterfaces()) {
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);
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) {
@ -156,7 +160,8 @@ public class ASTFactory {
List<FormalParameter> params = new ArrayList<>();
int i = 0;
for (Type jreParam : jreGenericParams) {
if (jreParam == null) continue;
if (jreParam == null)
continue;
RefTypeOrTPHOrWildcardOrGeneric paramType = createType(jreParam);
params.add(new FormalParameter(jreParams[i].getName(), paramType, new NullToken()));
i++;
@ -189,7 +194,8 @@ public class ASTFactory {
List<FormalParameter> params = new ArrayList<>();
int i = 0;
for (Type jreParam : jreGenericParams) {
if (jreParam == null) continue;
if (jreParam == null)
continue;
RefTypeOrTPHOrWildcardOrGeneric paramType = createType(jreParam);
params.add(new FormalParameter(jreParams[i].getName(), paramType, new NullToken()));
i++;
@ -217,7 +223,8 @@ public class ASTFactory {
}
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 signatureVisitor = new SignatureVisitor(Opcodes.ASM7) {
@ -226,7 +233,8 @@ public class ASTFactory {
final Stack<RefType> classTypes = new Stack<>();
// All hail the mighty visitor pattern
final SignatureVisitor doNothing = new SignatureVisitor(Opcodes.ASM7) {};
final SignatureVisitor doNothing = new SignatureVisitor(Opcodes.ASM7) {
};
char wildcard = '=';
@ -404,48 +412,26 @@ public class ASTFactory {
}
/*
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));
return ASTFactory.createConstructor(parent, new ParameterList(), block);
}
public static Constructor createConstructor(Class superClass, ParameterList paralist, Block block){
block.parserPostProcessing(superClass);
Method method = ASTFactory.createMethod("<init>", paralist, block, superClass);
method.setType(new de.dhbwstuttgart.syntaxtree.type.Void(block, 0));
return new Constructor(method, 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));
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();
}
* 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));
*
* return ASTFactory.createConstructor(parent, new ParameterList(), block); }
*
* public static Constructor createConstructor(Class superClass, ParameterList paralist, Block block){ block.parserPostProcessing(superClass);
*
* Method method = ASTFactory.createMethod("<init>", paralist, block, superClass); method.setType(new de.dhbwstuttgart.syntaxtree.type.Void(block, 0));
*
* return new Constructor(method, 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));
*
* 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
public void generateBC() throws Exception {
/*SourceFile sf = generateAST();
PositionFinder.getPositionOfTPH(sf, null);
TPHExtractor tphExtractor = new TPHExtractor();
List<ResultSet> results = new ArrayList<ResultSet>();
GeneratedGenericsFinder generatedGenericsFinder = new GeneratedGenericsFinder(sf, results);*/
/*
* SourceFile sf = generateAST(); PositionFinder.getPositionOfTPH(sf, null); TPHExtractor tphExtractor = new TPHExtractor(); List<ResultSet> results = new ArrayList<ResultSet>(); GeneratedGenericsFinder generatedGenericsFinder = new GeneratedGenericsFinder(sf, results);
*/
}
public static SourceFile generateAST() {
@ -33,10 +31,7 @@ public class FamilyOfGenerics {
String[] paramNames = { "a" };
methods.add(generateMethod("testMethode", paramNames));
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 NullToken()));
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()));
return new SourceFile("Test.jav", classes, new HashSet<>());
}
@ -49,8 +44,7 @@ public class FamilyOfGenerics {
}
ParameterList parameterList = new ParameterList(parameters, new NullToken());
return new Method(Modifier.PUBLIC, methodName, TypePlaceholder.fresh(new NullToken()), parameterList,
new Block(new ArrayList<>(), new NullToken()), generateEmptyGenericDeclList(), new NullToken());
return new Method(Modifier.PUBLIC, methodName, TypePlaceholder.fresh(new NullToken()), parameterList, new Block(new ArrayList<>(), new NullToken()), generateEmptyGenericDeclList(), new NullToken());
}
public static GenericDeclarationList generateEmptyGenericDeclList() {

View File

@ -25,7 +25,7 @@ public class ASTToTypedTargetAST {
@Test
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<>());
TargetClass emptyTargetClass = new ASTToTargetAST(List.of(emptyResultSet)).convert(emptyClass);
assert emptyTargetClass.getName().equals("EmptyClass");