diff --git a/src/main/antlr4/de/dhbwstuttgart/parser/antlr/Java17Parser.g4 b/src/main/antlr4/de/dhbwstuttgart/parser/antlr/Java17Parser.g4 index 64275b2f..37f7168d 100644 --- a/src/main/antlr4/de/dhbwstuttgart/parser/antlr/Java17Parser.g4 +++ b/src/main/antlr4/de/dhbwstuttgart/parser/antlr/Java17Parser.g4 @@ -34,8 +34,8 @@ parser grammar Java17Parser; options { tokenVocab=Java17Lexer; } sourceFile - : packageDeclaration? importDeclaration* classOrInterface* - | moduleDeclaration EOF + : packageDeclaration? importDeclaration* classOrInterface* # srcfile + | moduleDeclaration EOF # moduledecl ; packageDeclaration @@ -48,16 +48,16 @@ importDeclaration classOrInterface : classOrInterfaceModifier* - (classDeclaration | enumDeclaration | interfaceDeclaration | annotationTypeDeclaration | recordDeclaration) - | ';' + (classDeclaration | enumDeclaration | interfaceDeclaration | annotationTypeDeclaration | recordDeclaration) # classorinterfacedecl + | ';' # noclassorinterface ; modifier : classOrInterfaceModifier - | NATIVE - | SYNCHRONIZED - | TRANSIENT - | VOLATILE + | NATIVE + | SYNCHRONIZED + | TRANSIENT + | VOLATILE ; classOrInterfaceModifier @@ -67,15 +67,15 @@ classOrInterfaceModifier | PRIVATE | STATIC | ABSTRACT - | FINAL // FINAL for class only -- does not apply to interfaces + | FINAL // FINAL for class only -- does not apply to interfaces | STRICTFP - | SEALED // Java17 - | NON_SEALED // Java17 + | SEALED // Java17 + | NON_SEALED // Java17 ; variableModifier - : FINAL - | annotation + : FINAL # finalvarmod + | annotation # annotationvarmod ; classDeclaration @@ -127,21 +127,21 @@ interfaceBody ; classBodyDeclaration - : ';' - | STATIC? block - | modifier* memberDeclaration + : ';' # emptyclassbody + | STATIC? block # classblock + | modifier* memberDeclaration # memberdecl ; memberDeclaration - : classOrInterface - | fieldDeclaration - | method - | constructor + : classOrInterface # memberclassorinterface + | fieldDeclaration # memberfield + | method # membermethod + | constructor # memberconstructor ; method - : methodDeclaration - | genericMethodDeclaration + : methodDeclaration # methoddecl + | genericMethodDeclaration # genericmethod ; /* We use rule this even for void methods which cannot have [] after parameters. @@ -150,19 +150,23 @@ method for invalid return type after parsing. */ methodDeclaration - : refType? identifier formalParameters ('[' ']')* + : methodHeader (THROWS exceptionList)? methodBody ; +methodHeader + : refType? identifier formalParameters ('[' ']')* + ; + methodBody - : block - | ';' + : block # methodblock + | ';' # emptymethod ; refType - : typeType - | VOID + : typeType # reftype + | VOID # refvoid ; genericMethodDeclaration @@ -170,8 +174,8 @@ genericMethodDeclaration ; constructor - : genericConstructorDeclaration - | constructorDeclaration + : genericConstructorDeclaration # genericconstructor + | constructorDeclaration # constructordecl ; genericConstructorDeclaration @@ -187,19 +191,19 @@ fieldDeclaration ; interfaceBodyDeclaration - : modifier* interfaceMemberDeclaration - | ';' + : modifier* interfaceMemberDeclaration # interfacemember + | ';' # emptyinterface ; interfaceMemberDeclaration - : constDeclaration - | interfaceMethodDeclaration - | genericInterfaceMethodDeclaration - | interfaceDeclaration - | annotationTypeDeclaration - | classDeclaration - | enumDeclaration - | recordDeclaration // Java17 + : constDeclaration # interfaceconst + | interfaceMethodDeclaration # interfacemethod + | genericInterfaceMethodDeclaration # genericinterfacemethod + | interfaceDeclaration # subinterface + | annotationTypeDeclaration # interfaceannotationtype + | classDeclaration # interfaceclass + | enumDeclaration # interfaceenum + | recordDeclaration # interfacerecord // Java17 ; constDeclaration diff --git a/src/main/java/de/dhbwstuttgart/parser/SyntaxTreeGenerator/ASTGen.java b/src/main/java/de/dhbwstuttgart/parser/SyntaxTreeGenerator/ASTGen.java new file mode 100644 index 00000000..b447e1c2 --- /dev/null +++ b/src/main/java/de/dhbwstuttgart/parser/SyntaxTreeGenerator/ASTGen.java @@ -0,0 +1,140 @@ +package de.dhbwstuttgart.parser.SyntaxTreeGenerator; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.List; +import java.lang.reflect.Modifier; +import java.util.ArrayList; + +import de.dhbwstuttgart.environment.PackageCrawler; +import de.dhbwstuttgart.parser.antlr.Java17Parser; +import de.dhbwstuttgart.parser.antlr.Java17ParserBaseVisitor; +import de.dhbwstuttgart.parser.antlr.Java17Parser.AnnotationclassmodContext; +import de.dhbwstuttgart.parser.antlr.Java17Parser.ClassOrInterfaceModifierContext; +import de.dhbwstuttgart.parser.antlr.Java17Parser.ClassorinterfacedeclContext; +import de.dhbwstuttgart.parser.antlr.Java17Parser.ClassorinterfacemodContext; +import de.dhbwstuttgart.parser.antlr.Java17Parser.ModifierContext; +import de.dhbwstuttgart.parser.antlr.Java17Parser.NoclassorinterfaceContext; +import de.dhbwstuttgart.parser.scope.GatherNames; +import de.dhbwstuttgart.parser.scope.GenericsRegistry; +import de.dhbwstuttgart.parser.scope.JavaClassName; +import de.dhbwstuttgart.parser.scope.JavaClassRegistry; +import de.dhbwstuttgart.syntaxtree.ClassOrInterface; +import de.dhbwstuttgart.syntaxtree.SourceFile; +import de.dhbwstuttgart.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric; +import de.dhbwstuttgart.syntaxtree.statement.Statement; + +public class ASTGen extends Java17ParserBaseVisitor { + private JavaClassRegistry reg; + private final GenericsRegistry globalGenerics; + private String pkgName = ""; + Set imports = new HashSet<>(); + // PL 2018-11-01 fields eingefuegt, damit die fields immer die gleiche TPH + // bekommen + private Map fields = new HashMap<>(); + // PL 2019-10-23: Muss für jede Klasse neu initilisiert werden + List fieldInitializations = new ArrayList<>(); + + public ASTGen(JavaClassRegistry reg, GenericsRegistry globalGenerics) { + // Die Generics müssen während des Bauens des AST erstellt werden, + // da diese mit der Methode oder Klasse, in welcher sie deklariert werden + // verknüpft sein müssen. Dennoch werden die Namen aller Generics in einer + // globalen Datenbank benötigt. + this.globalGenerics = globalGenerics; + this.reg = reg; + } + + public JavaClassRegistry getReg() { + return this.reg; + } + + public String convertQualifiedName(Java17Parser.QualifiedNameContext ctx) { + String ret = ""; + for (Java17Parser.IdentifierContext ident : ctx.identifier()) { + ret += ident.getText(); + if (ctx.identifier().iterator().hasNext()) { + ret += '.'; + } + } + return ret; + } + + public SourceFile generate(Java17Parser.SourceFileContext ctx, PackageCrawler packageCrawler, ClassLoader classLoader) + throws ClassNotFoundException { + List classes = new ArrayList<>(); + Map imports = GatherNames.getImports(ctx, packageCrawler, classLoader); + this.imports = imports.keySet().stream().map(name -> reg.getName(name)).collect(Collectors.toSet()); + + return (SourceFile) this.visit(ctx); + } + + @Override + public SourceFile visitSrcfile(Java17Parser.SrcfileContext ctx) { + for (Java17Parser.ClassOrInterfaceContext member : ctx.classOrInterface()) { + ClassorinterfacedeclContext clsoif; + if (member instanceof NoclassorinterfaceContext) { + continue; + } else { + clsoif = new ClassorinterfacedeclContext(member); + } + ClassOrInterface newClass; + int modifiers = 0; + if (!clsoif.classOrInterfaceModifier().isEmpty()) { + for (Java17Parser.ClassOrInterfaceModifierContext mod : clsoif.classOrInterfaceModifier()) { + int newModifier = (Integer) visit(mod); + modifiers += newModifier; + } + } + fieldInitializations = new ArrayList<>(); // PL 2019-10-22: muss für jede Klasse neu initilisiert werden + if (clsoif.classDeclaration() != null) { + newClass = convertClass(clsoif.classDeclaration()); + } else { + newClass = convertInterface(clsoif.interfaceDeclaration()); + } + classes.add(newClass); + } + return new SourceFile(this.pkgName, classes, this.imports); + } + + @Override + public Object visitModifier(ModifierContext ctx) { + if (ctx.classOrInterfaceModifier() != null) { + return visit(ctx.classOrInterfaceModifier()); + } else { + return convertModifier(ctx.getText()); + } + } + + @Override + public Object visitClassOrInterfaceModifier(ClassOrInterfaceModifierContext ctx) { + if (ctx.annotation() != null) + return 0; + return convertModifier(ctx.getText()); + } + + public static int convertModifier(String modifier) { + HashMap modifiers = new HashMap<>(); + modifiers.put(Modifier.toString(Modifier.PUBLIC), Modifier.PUBLIC); + modifiers.put(Modifier.toString(Modifier.PRIVATE), Modifier.PRIVATE); + modifiers.put(Modifier.toString(Modifier.PROTECTED), Modifier.PROTECTED); + modifiers.put(Modifier.toString(Modifier.ABSTRACT), Modifier.ABSTRACT); + modifiers.put(Modifier.toString(Modifier.STATIC), Modifier.STATIC); + modifiers.put(Modifier.toString(Modifier.STRICT), Modifier.STRICT); + modifiers.put(Modifier.toString(Modifier.FINAL), Modifier.FINAL); + modifiers.put(Modifier.toString(Modifier.TRANSIENT), Modifier.TRANSIENT); + modifiers.put(Modifier.toString(Modifier.VOLATILE), Modifier.VOLATILE); + modifiers.put(Modifier.toString(Modifier.SYNCHRONIZED), Modifier.SYNCHRONIZED); + modifiers.put(Modifier.toString(Modifier.NATIVE), Modifier.NATIVE); + modifiers.put(Modifier.toString(Modifier.INTERFACE), Modifier.INTERFACE); + int ret = 0; + for (String m : modifiers.keySet()) { + if (modifier.contains(m)) + ret += modifiers.get(m); + } + return ret; + } + +}