From eaef00ff54f5d71be089ce274bc697188b388838 Mon Sep 17 00:00:00 2001 From: Daniel Holle Date: Mon, 23 Oct 2023 16:44:12 +0200 Subject: [PATCH] Static but no static blocks yet --- resources/bytecode/javFiles/Static.jav | 9 ++++ .../de/dhbwstuttgart/bytecode/Codegen.java | 22 +++++++- .../de/dhbwstuttgart/core/JavaTXCompiler.java | 24 +++++++-- .../SyntaxTreeGenerator/FieldEntry.java | 6 +++ .../StatementGenerator.java | 38 +++++++++---- .../SyntaxTreeGenerator.java | 54 ++++++++++++------- .../syntaxtree/ClassOrInterface.java | 21 +++++--- .../de/dhbwstuttgart/syntaxtree/Record.java | 6 ++- .../syntaxtree/factory/ASTFactory.java | 2 +- .../syntaxtree/statement/FieldVar.java | 4 +- .../target/generate/ASTToTargetAST.java | 10 ++-- .../generate/StatementToTargetExpression.java | 2 +- .../target/tree/TargetClass.java | 6 +-- .../target/tree/TargetInterface.java | 2 +- .../target/tree/TargetRecord.java | 2 +- .../target/tree/TargetStructure.java | 3 ++ .../typeinference/assumptions/FunNClass.java | 3 +- .../typeinference/typeAlgo/TYPE.java | 4 ++ src/test/java/TestComplete.java | 8 ++- .../java/targetast/ASTToTypedTargetAST.java | 8 +-- 20 files changed, 170 insertions(+), 64 deletions(-) create mode 100644 resources/bytecode/javFiles/Static.jav create mode 100644 src/main/java/de/dhbwstuttgart/parser/SyntaxTreeGenerator/FieldEntry.java diff --git a/resources/bytecode/javFiles/Static.jav b/resources/bytecode/javFiles/Static.jav new file mode 100644 index 00000000..a0c00c25 --- /dev/null +++ b/resources/bytecode/javFiles/Static.jav @@ -0,0 +1,9 @@ +import java.lang.Integer; + +public class Static { + static i = 20; + + static m() { + return i; + } +} diff --git a/src/main/java/de/dhbwstuttgart/bytecode/Codegen.java b/src/main/java/de/dhbwstuttgart/bytecode/Codegen.java index d02598d6..535c1ad7 100644 --- a/src/main/java/de/dhbwstuttgart/bytecode/Codegen.java +++ b/src/main/java/de/dhbwstuttgart/bytecode/Codegen.java @@ -599,7 +599,7 @@ public class Codegen { switch (op) { case TargetUnaryOp.Add add -> // This literally does nothing - generate(state, add.expr()); + generate(state, add.expr()); case TargetUnaryOp.Negate negate -> { generate(state, negate.expr()); if (negate.type().equals(TargetType.Double)) @@ -834,7 +834,8 @@ public class Codegen { } case TargetFieldVar dot -> { var fieldType = dot.type(); - generate(state, dot.left()); + if (!(dot.left() instanceof TargetThis && dot.isStatic())) + generate(state, dot.left()); generate(state, assign.right()); convertTo(state, assign.right().type(), fieldType); boxPrimitive(state, fieldType); @@ -1290,6 +1291,20 @@ public class Codegen { cw.visitField(access, field.name(), field.type().toSignature(), field.type().toDescriptor(), null); } + private void generateStaticConstructor(TargetMethod constructor) { + MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "", "()V", null, null); + mv.visitCode(); + + var state = new State(null, mv, 0); + var stmts = constructor.block().statements(); + for (var i = 1; i < stmts.size(); i++) + generate(state, stmts.get(i)); + + mv.visitInsn(RETURN); + mv.visitMaxs(0, 0); + mv.visitEnd(); + } + private void generateConstructor(TargetConstructor constructor) { MethodVisitor mv = cw.visitMethod(constructor.access() | ACC_PUBLIC, "", constructor.getDescriptor(), constructor.getSignature(), null); if (constructor.txGenerics() != null) @@ -1407,6 +1422,9 @@ public class Codegen { clazz.constructors().forEach(this::generateConstructor); clazz.methods().forEach(this::generateMethod); + if (clazz.staticConstructor() != null) + generateStaticConstructor(clazz.staticConstructor()); + if (clazz instanceof TargetRecord) generateRecordMethods(); diff --git a/src/main/java/de/dhbwstuttgart/core/JavaTXCompiler.java b/src/main/java/de/dhbwstuttgart/core/JavaTXCompiler.java index c38dd936..e161f7a2 100644 --- a/src/main/java/de/dhbwstuttgart/core/JavaTXCompiler.java +++ b/src/main/java/de/dhbwstuttgart/core/JavaTXCompiler.java @@ -70,6 +70,9 @@ public class JavaTXCompiler { final CompilationEnvironment environment; Boolean resultmodel = false; public final Map sourceFiles = new HashMap<>(); + // TODO We might want to incorporate this into the class registry instead + public final Map classes = new HashMap<>(); + Boolean log = true; //gibt an ob ein Log-File nach System.getProperty("user.dir")+""/logFiles/"" geschrieben werden soll? public volatile UnifyTaskModel usedTasks = new UnifyTaskModel(); private final DirectoryClassLoader classLoader; @@ -103,11 +106,22 @@ public class JavaTXCompiler { classPath = contextPath; for (File s : sources) { - sourceFiles.put(s, parse(s)); + addSourceFile(s, parse(s)); } // INSTANCE = this; } + private void addSourceFile(File file, SourceFile sf) { + sourceFiles.put(file, sf); + for (var clazz : sf.KlassenVektor) { + classes.put(clazz.getClassName(), clazz); + } + } + + public ClassOrInterface getClass(JavaClassName name) { + return classes.get(name); + } + public ConstraintSet getConstraints() throws ClassNotFoundException, IOException { List allClasses = new ArrayList<>();// environment.getAllAvailableClasses(); List importedClasses = new ArrayList<>(); @@ -630,8 +644,8 @@ public class JavaTXCompiler { private SourceFile parse(File sourceFile) throws IOException, java.lang.ClassNotFoundException { SourceFileContext tree = JavaTXParser.parse(sourceFile); environment.addClassesToRegistry(classRegistry, tree, sourceFile, this); - SyntaxTreeGenerator generator = new SyntaxTreeGenerator(classRegistry, new GenericsRegistry(null)); - SourceFile ret = generator.convert(tree, environment.packageCrawler, this); + SyntaxTreeGenerator generator = new SyntaxTreeGenerator(this, classRegistry, new GenericsRegistry(null)); + SourceFile ret = generator.convert(tree, environment.packageCrawler); return ret; } @@ -651,8 +665,8 @@ public class JavaTXCompiler { var tree = JavaTXParser.parse(file); classRegistry.addName(name.toString(), 0); // TODO This gets overwritten later, is it bad if we don't know this right away? environment.addClassesToRegistry(classRegistry, tree, file, this); - SyntaxTreeGenerator generator = new SyntaxTreeGenerator(classRegistry, new GenericsRegistry(null)); - sourceFiles.put(file, generator.convert(tree, environment.packageCrawler, this)); + SyntaxTreeGenerator generator = new SyntaxTreeGenerator(this, classRegistry, new GenericsRegistry(null)); + addSourceFile(file, generator.convert(tree, environment.packageCrawler)); return true; } catch (Exception e) { throw new RuntimeException(e); diff --git a/src/main/java/de/dhbwstuttgart/parser/SyntaxTreeGenerator/FieldEntry.java b/src/main/java/de/dhbwstuttgart/parser/SyntaxTreeGenerator/FieldEntry.java new file mode 100644 index 00000000..466dc614 --- /dev/null +++ b/src/main/java/de/dhbwstuttgart/parser/SyntaxTreeGenerator/FieldEntry.java @@ -0,0 +1,6 @@ +package de.dhbwstuttgart.parser.SyntaxTreeGenerator; + +import de.dhbwstuttgart.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric; + +public record FieldEntry(String name, RefTypeOrTPHOrWildcardOrGeneric type, int modifiers) { +} diff --git a/src/main/java/de/dhbwstuttgart/parser/SyntaxTreeGenerator/StatementGenerator.java b/src/main/java/de/dhbwstuttgart/parser/SyntaxTreeGenerator/StatementGenerator.java index ab34ed9c..56d03576 100644 --- a/src/main/java/de/dhbwstuttgart/parser/SyntaxTreeGenerator/StatementGenerator.java +++ b/src/main/java/de/dhbwstuttgart/parser/SyntaxTreeGenerator/StatementGenerator.java @@ -1,5 +1,6 @@ package de.dhbwstuttgart.parser.SyntaxTreeGenerator; +import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; @@ -8,6 +9,7 @@ import java.util.Map; import java.util.Objects; import java.util.stream.Collectors; +import de.dhbwstuttgart.core.JavaTXCompiler; import de.dhbwstuttgart.syntaxtree.*; import de.dhbwstuttgart.syntaxtree.type.Void; import org.antlr.v4.runtime.Token; @@ -134,17 +136,24 @@ import de.dhbwstuttgart.syntaxtree.type.TypePlaceholder; public class StatementGenerator { - private JavaClassRegistry reg; - private Map fields; // PL 2018-11-01 fields eingefuegt, damit die fields - // immer die gleiche TPH bekommen - private Map localVars; - private GenericsRegistry generics; + private final JavaClassRegistry reg; - public StatementGenerator(JavaClassRegistry reg, GenericsRegistry generics, Map fields, Map localVars) { + private final Map fields; // PL 2018-11-01 fields eingefuegt, damit die fields + // immer die gleiche TPH bekommen + private final Map localVars; + private final GenericsRegistry generics; + private final JavaTXCompiler compiler; + + private final RefType superClass; + + // TODO How about instead of passing all of these types we just pass an instance of the SyntaxTreeGenerator? + public StatementGenerator(RefType superType, JavaTXCompiler compiler, JavaClassRegistry reg, GenericsRegistry generics, Map fields, Map localVars) { this.reg = reg; this.generics = generics; this.fields = fields; this.localVars = localVars; + this.compiler = compiler; + this.superClass = superType; } public ParameterList convert(Java17Parser.FormalParameterListContext formalParameterListContext) { @@ -574,7 +583,8 @@ public class StatementGenerator { } else { initValue = convert(varDecl.variableInitializer().expression()); } - return (new Assign(new AssignToField(new FieldVar(new This(varDecl.getStart()), name.getText(), type, varDecl.getStart())), initValue, name.getStart())); + var fieldEntry = fields.get(name.getText()); + return (new Assign(new AssignToField(new FieldVar(new This(varDecl.getStart()), (fieldEntry.modifiers() & Modifier.STATIC) != 0, name.getText(), type, varDecl.getStart())), initValue, name.getStart())); } private Statement convert(Java17Parser.BreakstmtContext stmt) { @@ -760,7 +770,8 @@ public class StatementGenerator { return new LocalVar(expression, localVars.get(expression), offset); } else if (fields.get(expression) != null) {// PL 2018-11-01 fields eingefuegt, damit die fields immer die // gleiche TPH bekommen - return new FieldVar(new This(offset), expression, fields.get(expression), offset); + var field = fields.get(expression); + return new FieldVar(new This(offset), Modifier.isStatic(field.modifiers()), expression, fields.get(expression).type(), offset); } else { // lokale Variable wurde ohne "var"-Keyword deklariert und direkt mit Wert versehen @@ -783,16 +794,23 @@ public class StatementGenerator { } whole += "."; } + var fieldName = parts[parts.length - 1]; + var isStatic = false; if (parts.length < 2 || parts[0].contentEquals("this")) { receiver = new This(offset); + isStatic = Modifier.isStatic(fields.get(fieldName).modifiers()); } else if (parts[0].contentEquals("super")) { receiver = new Super(offset); + isStatic = Modifier.isStatic(compiler.getClass(new JavaClassName(superClass.getName().toString())).getField(fieldName).orElseThrow().modifier); } else if (receiver == null) { // Handelt es sich um keinen Statischen Klassennamen: String part = expression.substring(0, expression.length() - (1 + parts[parts.length - 1].length())); receiver = generateLocalOrFieldVarOrClassName(part, offset); + } else { + StaticClassName cname = (StaticClassName) receiver; + isStatic = Modifier.isStatic(compiler.getClass(reg.getName(cname.getType().toString())).getField(fieldName).orElseThrow().modifier); } - return new FieldVar(receiver, parts[parts.length - 1], TypePlaceholder.fresh(offset), offset); + return new FieldVar(receiver, isStatic, fieldName, TypePlaceholder.fresh(offset), offset); } private Expression convert(Java17Parser.ArrayaccessexpressionContext arrayaccess) { @@ -1063,7 +1081,7 @@ public class StatementGenerator { if (!(param instanceof FormalParameter fp)) throw new IllegalArgumentException(); lambdaLocals.put(fp.getName(), fp.getType()); } - StatementGenerator lambdaGenerator = new StatementGenerator(reg, generics, fields, lambdaLocals); + StatementGenerator lambdaGenerator = new StatementGenerator(superClass, compiler, reg, generics, fields, lambdaLocals); Block block; if (expression.lambdaBody().expression() != null) { diff --git a/src/main/java/de/dhbwstuttgart/parser/SyntaxTreeGenerator/SyntaxTreeGenerator.java b/src/main/java/de/dhbwstuttgart/parser/SyntaxTreeGenerator/SyntaxTreeGenerator.java index 6fb89b23..d047e645 100644 --- a/src/main/java/de/dhbwstuttgart/parser/SyntaxTreeGenerator/SyntaxTreeGenerator.java +++ b/src/main/java/de/dhbwstuttgart/parser/SyntaxTreeGenerator/SyntaxTreeGenerator.java @@ -13,6 +13,7 @@ import java.util.Set; import java.util.stream.Collectors; import de.dhbwstuttgart.core.JavaTXCompiler; +import de.dhbwstuttgart.parser.NullToken; import de.dhbwstuttgart.syntaxtree.*; import de.dhbwstuttgart.syntaxtree.Record; import org.antlr.v4.runtime.CommonToken; @@ -91,11 +92,15 @@ public class SyntaxTreeGenerator { HashMap allmodifiers = new HashMap<>(); // PL 2018-11-01 fields eingefuegt, damit die fields immer die gleiche TPH // bekommen - private Map fields = new HashMap<>(); + private final Map fields = new HashMap<>(); // PL 2019-10-23: Muss für jede Klasse neu initilisiert werden List fieldInitializations = new ArrayList<>(); + List staticFieldInitializations = new ArrayList<>(); - public SyntaxTreeGenerator(JavaClassRegistry reg, GenericsRegistry globalGenerics) { + private final JavaTXCompiler compiler; + private RefType superClass; + + public SyntaxTreeGenerator(JavaTXCompiler compiler, 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 @@ -118,6 +123,8 @@ public class SyntaxTreeGenerator { this.allmodifiers.put("non-sealed", 8192); this.allmodifiers.put("default", 16384); this.allmodifiers.put("strictfp", 32768); + + this.compiler = compiler; } public JavaClassRegistry getReg() { @@ -131,7 +138,7 @@ public class SyntaxTreeGenerator { return ctx.getText(); } - public SourceFile convert(Java17Parser.SourceFileContext ctx, PackageCrawler packageCrawler, JavaTXCompiler compiler) throws ClassNotFoundException, NotImplementedException { + public SourceFile convert(Java17Parser.SourceFileContext ctx, PackageCrawler packageCrawler) throws ClassNotFoundException, NotImplementedException { SrcfileContext srcfile; List classes = new ArrayList<>(); if (ctx instanceof Java17Parser.SrcfileContext) { @@ -200,6 +207,7 @@ public class SyntaxTreeGenerator { } else { superClass = new RefType(ASTFactory.createObjectClass().getClassName(), ctx.getStart()); } + this.superClass = superClass; List fielddecl = new ArrayList<>(); List methods = new ArrayList<>(); List constructors = new ArrayList<>(); @@ -225,11 +233,14 @@ public class SyntaxTreeGenerator { throw new NotImplementedException("Invalid sealed class declaration"); } } - 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); + var ctor = Optional.of(this.generatePseudoConstructor(ctx.identifier().getText(), fieldInitializations, genericClassParameters, offset)); + var staticCtor = Optional.of(this.generatePseudoConstructor(ctx.identifier().getText(), staticFieldInitializations, genericClassParameters, offset)); + return new ClassOrInterface(modifiers, name, fielddecl, ctor, staticCtor, methods, constructors, genericClassParameters, superClass, isInterface, implementedInterfaces, permittedSubtypes, offset); } private de.dhbwstuttgart.syntaxtree.Record convertRecord(RecordDeclarationContext recordDeclaration, int modifiers) { + this.superClass = new RefType(new JavaClassName("java.lang.Record"), new NullToken()); String identifier = recordDeclaration.identifier().getText(); String className = this.pkgName + (this.pkgName.length() > 0 ? "." : "") + identifier; JavaClassName name = reg.getName(className); // Holt den Package Namen mit dazu @@ -264,7 +275,7 @@ public class SyntaxTreeGenerator { } fielddecl.add(new Field(fieldname, fieldtype, fieldmodifiers, fieldoffset)); constructorParameters.add(new FormalParameter(fieldname, fieldtype, fieldoffset)); - FieldVar fieldvar = new FieldVar(new This(offset), fieldname, fieldtype, fieldoffset); + FieldVar fieldvar = new FieldVar(new This(offset), false, fieldname, fieldtype, fieldoffset); constructorStatements.add(new Assign(new AssignToField(fieldvar), new LocalVar(fieldname, fieldtype, fieldoffset), offset)); Statement returnStatement = new Return(fieldvar, offset); methods.add(new Method(allmodifiers.get("public"), fieldname, fieldtype, new ParameterList(new ArrayList<>(), offset), new Block(Arrays.asList(returnStatement), offset), new GenericDeclarationList(new ArrayList<>(), offset), offset)); @@ -279,7 +290,8 @@ public class SyntaxTreeGenerator { if (!Objects.isNull(recordDeclaration.IMPLEMENTS())) { implementedInterfaces.addAll(convert(recordDeclaration.typeList(), generics)); } - return new Record(modifiers, name, fielddecl, initializations, methods, constructors, genericClassParameters, superClass, isInterface, implementedInterfaces, offset); + var staticCtor = Optional.of(this.generatePseudoConstructor(recordDeclaration.identifier().getText(), staticFieldInitializations, genericClassParameters, offset)); + return new Record(modifiers, name, fielddecl, initializations, staticCtor, methods, constructors, genericClassParameters, superClass, isInterface, implementedInterfaces, offset); } private void convert(ClassBodyDeclarationContext classBody, List fields, List constructors, List methods, JavaClassName name, RefType superClass, GenericsRegistry generics) { @@ -319,6 +331,7 @@ public class SyntaxTreeGenerator { } private ClassOrInterface convertInterface(Java17Parser.InterfaceDeclarationContext ctx, int modifiers) { + this.superClass = new RefType(new JavaClassName("java.lang.Object"), new NullToken()); String className = this.pkgName.length() > 0 ? this.pkgName + "." : "" + ctx.identifier().getText(); JavaClassName name = reg.getName(className); // Holt den Package Namen mit dazu if (!name.toString().equals(className)) { // Kommt die Klasse schon in einem anderen Package vor? @@ -391,7 +404,9 @@ public class SyntaxTreeGenerator { 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()); + + var staticCtor = Optional.of(this.generatePseudoConstructor(ctx.identifier().getText(), staticFieldInitializations, genericParams, ctx.getStart())); + return new ClassOrInterface(modifiers, name, fields, Optional.empty(), staticCtor, methods, new ArrayList<>(), genericParams, superClass, true, extendedInterfaces, permittedSubtypes, ctx.getStart()); } private GenericDeclarationList createEmptyGenericDeclarationList(Token classNameIdentifier) { @@ -419,7 +434,7 @@ public class SyntaxTreeGenerator { retType = new Void(bodydeclaration.refType().getStart()); } } - StatementGenerator stmtgen = new StatementGenerator(reg, generics, fields, new HashMap<>()); + StatementGenerator stmtgen = new StatementGenerator(superClass, compiler, reg, generics, fields, new HashMap<>()); ParameterList paramlist = stmtgen.convert(bodydeclaration.formalParameters().formalParameterList()); MethodBodyContext body = bodydeclaration.methodBody(); Block block = null; @@ -447,10 +462,10 @@ public class SyntaxTreeGenerator { /* * fieldInitializations werden in einem Psedokonstruktor in der abstrakten Syntax gespeichert */ - private Constructor generatePseudoConstructor(String className, JavaClassName parentClass, RefType superClass, GenericDeclarationList classGenerics, Token offset) { + private Constructor generatePseudoConstructor(String className, List initializations, GenericDeclarationList classGenerics, Token offset) { RefType classType = ClassOrInterface.generateTypeOfClass(reg.getName(className), classGenerics, offset); ParameterList params = new ParameterList(new ArrayList<>(), offset); - Block block = new Block(new ArrayList<>(fieldInitializations), offset); + Block block = new Block(new ArrayList<>(initializations), offset); return new Constructor(Modifier.PUBLIC, className, classType, params, block, classGenerics, offset /* * fieldInitializations geloescht PL 2018-11-24 */); @@ -512,7 +527,7 @@ public class SyntaxTreeGenerator { retType = new Void(header.refType().getStart()); } } - StatementGenerator stmtgen = new StatementGenerator(reg, localgenerics, fields, new HashMap<>()); + StatementGenerator stmtgen = new StatementGenerator(superClass, compiler, reg, localgenerics, fields, new HashMap<>()); ParameterList paramlist = stmtgen.convert(header.formalParameters().formalParameterList()); MethodBodyContext body = methoddeclaration.methodBody(); Block block = null; @@ -552,13 +567,13 @@ public class SyntaxTreeGenerator { gtvDeclarations = new GenericDeclarationList(new ArrayList<>(), constructordeclaration.getStart()); } RefTypeOrTPHOrWildcardOrGeneric retType = TypeGenerator.convertTypeName(name, constructordeclaration.getStart(), reg, localgenerics); - StatementGenerator stmtgen = new StatementGenerator(reg, localgenerics, fields, new HashMap<>()); + StatementGenerator stmtgen = new StatementGenerator(superClass, compiler, reg, localgenerics, fields, new HashMap<>()); ParameterList paramlist = stmtgen.convert(constructordeclaration.formalParameters().formalParameterList()); Block block = stmtgen.convert(constructordeclaration.constructorBody, true); return new Constructor(modifiers, name, retType, paramlist, block, gtvDeclarations, constructordeclaration.getStart()); } - private List convert(Java17Parser.FieldDeclarationContext fieldDeclContext, int modifiers, GenericsRegistry generics) { + List convert(Java17Parser.FieldDeclarationContext fieldDeclContext, int modifiers, GenericsRegistry generics) { List ret = new ArrayList<>(); RefTypeOrTPHOrWildcardOrGeneric fieldType; if (fieldDeclContext.typeType() != null) { @@ -570,9 +585,9 @@ public class SyntaxTreeGenerator { } for (Java17Parser.VariableDeclaratorContext varDecl : fieldDeclContext.variableDeclarators().variableDeclarator()) { String fieldName = varDecl.variableDeclaratorId().getText(); - this.fields.put(fieldName, fieldType); + this.fields.put(fieldName, new FieldEntry(fieldName, fieldType, modifiers)); if (varDecl.variableInitializer() != null) { - initializeField(varDecl, fieldType, generics); + initializeField(varDecl, Modifier.isStatic(modifiers), fieldType, generics); } ret.add(new Field(fieldName, fieldType, modifiers, varDecl.getStart())); } @@ -584,9 +599,12 @@ public class SyntaxTreeGenerator { } // Initialize a field by creating implicit constructor. - private void initializeField(Java17Parser.VariableDeclaratorContext ctx, RefTypeOrTPHOrWildcardOrGeneric typeOfField, GenericsRegistry generics) { - StatementGenerator statementGenerator = new StatementGenerator(reg, generics, fields, new HashMap<>()); - fieldInitializations.add(statementGenerator.generateFieldAssignment(ctx, typeOfField)); + private void initializeField(Java17Parser.VariableDeclaratorContext ctx, boolean isStatic, RefTypeOrTPHOrWildcardOrGeneric typeOfField, GenericsRegistry generics) { + StatementGenerator statementGenerator = new StatementGenerator(superClass, compiler, reg, generics, fields, new HashMap<>()); + var assignment = statementGenerator.generateFieldAssignment(ctx, typeOfField); + if (isStatic) + staticFieldInitializations.add(assignment); + else fieldInitializations.add(assignment); } public int convertModifier(String modifier) { diff --git a/src/main/java/de/dhbwstuttgart/syntaxtree/ClassOrInterface.java b/src/main/java/de/dhbwstuttgart/syntaxtree/ClassOrInterface.java index 7dfd75e3..f1eb5290 100644 --- a/src/main/java/de/dhbwstuttgart/syntaxtree/ClassOrInterface.java +++ b/src/main/java/de/dhbwstuttgart/syntaxtree/ClassOrInterface.java @@ -1,18 +1,11 @@ package de.dhbwstuttgart.syntaxtree; -import de.dhbwstuttgart.core.IItemWithOffset; -import de.dhbwstuttgart.exceptions.DebugException; import de.dhbwstuttgart.parser.NullToken; import de.dhbwstuttgart.parser.scope.JavaClassName; -import de.dhbwstuttgart.syntaxtree.statement.Statement; import de.dhbwstuttgart.syntaxtree.type.GenericRefType; import de.dhbwstuttgart.syntaxtree.type.RefType; import de.dhbwstuttgart.syntaxtree.type.TypePlaceholder; -import de.dhbwstuttgart.syntaxtree.visual.ASTPrinter; import de.dhbwstuttgart.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric; -import de.dhbwstuttgart.typeinference.constraints.Constraint; -import de.dhbwstuttgart.typeinference.constraints.ConstraintSet; -import de.dhbwstuttgart.typeinference.assumptions.TypeInferenceInformation; import org.antlr.v4.runtime.Token; import java.lang.reflect.Modifier; @@ -30,6 +23,7 @@ public class ClassOrInterface extends SyntaxTreeNode implements TypeScope { protected JavaClassName name; private List fields = new ArrayList<>(); private Optional fieldInitializations; // PL 2018-11-24: Noetig, um Bytecode fuer initializators nur einmal zu erzeugen + private Optional staticInitializer; private List methods = new ArrayList<>(); private GenericDeclarationList genericClassParameters; private RefType superClass; @@ -38,7 +32,7 @@ public class ClassOrInterface extends SyntaxTreeNode implements TypeScope { private List permittedSubtypes; private List constructors; - public ClassOrInterface(int modifiers, JavaClassName name, List fielddecl, Optional fieldInitializations, List methods, List constructors, GenericDeclarationList genericClassParameters, RefType superClass, Boolean isInterface, List implementedInterfaces, List permittedSubtypes, Token offset) { + public ClassOrInterface(int modifiers, JavaClassName name, List fielddecl, Optional fieldInitializations, Optional staticInitializer, List methods, List constructors, GenericDeclarationList genericClassParameters, RefType superClass, Boolean isInterface, List implementedInterfaces, List permittedSubtypes, Token offset) { super(offset); if (isInterface) { modifiers |= Modifier.INTERFACE | Modifier.ABSTRACT; @@ -47,6 +41,7 @@ public class ClassOrInterface extends SyntaxTreeNode implements TypeScope { this.name = name; this.fields = fielddecl; this.fieldInitializations = fieldInitializations; + this.staticInitializer = staticInitializer; this.genericClassParameters = genericClassParameters; this.superClass = superClass; this.isInterface = isInterface; @@ -65,6 +60,7 @@ public class ClassOrInterface extends SyntaxTreeNode implements TypeScope { this.name = cl.name; this.fields = new ArrayList<>(cl.fields); this.fieldInitializations = cl.fieldInitializations; + this.staticInitializer = cl.staticInitializer; this.genericClassParameters = cl.genericClassParameters; this.superClass = cl.superClass; this.isInterface = cl.isInterface; @@ -73,6 +69,15 @@ public class ClassOrInterface extends SyntaxTreeNode implements TypeScope { this.constructors = new ArrayList<>(cl.constructors); } + public Optional getField(String name) { + // TODO This should be a map + return fields.stream().filter(field -> field.getName().equals(name)).findFirst(); + } + + public Optional getStaticInitializer() { + return staticInitializer; + } + public boolean isInterface() { return (Modifier.INTERFACE & this.getModifiers()) != 0; } diff --git a/src/main/java/de/dhbwstuttgart/syntaxtree/Record.java b/src/main/java/de/dhbwstuttgart/syntaxtree/Record.java index 1b147306..7b1bdc80 100644 --- a/src/main/java/de/dhbwstuttgart/syntaxtree/Record.java +++ b/src/main/java/de/dhbwstuttgart/syntaxtree/Record.java @@ -9,9 +9,11 @@ import org.antlr.v4.runtime.Token; import de.dhbwstuttgart.parser.scope.JavaClassName; import de.dhbwstuttgart.syntaxtree.type.RefType; +import javax.swing.text.html.Option; + public class Record extends ClassOrInterface { - public Record(int modifiers, JavaClassName name, List fielddecl, Optional fieldInitializations, List methods, List constructors, GenericDeclarationList genericClassParameters, RefType superClass, Boolean isInterface, List implementedInterfaces, Token offset) { - super(modifiers, name, fielddecl, fieldInitializations, methods, constructors, genericClassParameters, superClass, isInterface, implementedInterfaces, new ArrayList<>(), offset); + public Record(int modifiers, JavaClassName name, List fielddecl, Optional fieldInitializations, Optional staticInitializer, List methods, List constructors, GenericDeclarationList genericClassParameters, RefType superClass, Boolean isInterface, List implementedInterfaces, Token offset) { + super(modifiers, name, fielddecl, fieldInitializations, staticInitializer, methods, constructors, genericClassParameters, superClass, isInterface, implementedInterfaces, new ArrayList<>(), offset); } } diff --git a/src/main/java/de/dhbwstuttgart/syntaxtree/factory/ASTFactory.java b/src/main/java/de/dhbwstuttgart/syntaxtree/factory/ASTFactory.java index 96f31cf7..09d72fe8 100644 --- a/src/main/java/de/dhbwstuttgart/syntaxtree/factory/ASTFactory.java +++ b/src/main/java/de/dhbwstuttgart/syntaxtree/factory/ASTFactory.java @@ -141,7 +141,7 @@ public class ASTFactory { Token offset = new NullToken(); // Braucht keinen Offset, da diese Klasse nicht aus einem Quellcode geparst wurde - var cinf = new ClassOrInterface(modifier, name, felder, Optional.empty() /* eingefuegt PL 2018-11-24 */, methoden, konstruktoren, genericDeclarationList, superClass, isInterface, implementedInterfaces, permittedSubtypes, offset); + var cinf = new ClassOrInterface(modifier, name, felder, Optional.empty() /* eingefuegt PL 2018-11-24 */, Optional.empty(), methoden, konstruktoren, genericDeclarationList, superClass, isInterface, implementedInterfaces, permittedSubtypes, offset); cache.put(jreClass, cinf); return cinf; } diff --git a/src/main/java/de/dhbwstuttgart/syntaxtree/statement/FieldVar.java b/src/main/java/de/dhbwstuttgart/syntaxtree/statement/FieldVar.java index 9380e951..cb98da4f 100644 --- a/src/main/java/de/dhbwstuttgart/syntaxtree/statement/FieldVar.java +++ b/src/main/java/de/dhbwstuttgart/syntaxtree/statement/FieldVar.java @@ -17,11 +17,13 @@ public class FieldVar extends Expression { public final String fieldVarName; public final Expression receiver; + public final boolean isStatic; - public FieldVar(Expression receiver, String fieldVarName, RefTypeOrTPHOrWildcardOrGeneric type, Token offset) { + public FieldVar(Expression receiver, boolean isStatic, String fieldVarName, RefTypeOrTPHOrWildcardOrGeneric type, Token offset) { super(type, offset); this.fieldVarName = fieldVarName; this.receiver = receiver; + this.isStatic = isStatic; } @Override diff --git a/src/main/java/de/dhbwstuttgart/target/generate/ASTToTargetAST.java b/src/main/java/de/dhbwstuttgart/target/generate/ASTToTargetAST.java index 21745c13..cb982fa0 100644 --- a/src/main/java/de/dhbwstuttgart/target/generate/ASTToTargetAST.java +++ b/src/main/java/de/dhbwstuttgart/target/generate/ASTToTargetAST.java @@ -144,11 +144,15 @@ public class ASTToTargetAST { var fields = input.getFieldDecl().stream().map(this::convert).toList(); var methods = groupOverloads(input.getMethods()).stream().map(this::convert).flatMap(List::stream).toList(); + TargetMethod staticConstructor = null; + if (input.getStaticInitializer().isPresent()) + staticConstructor = this.convert(input.getStaticInitializer().get()).get(0); + if (input instanceof Record) - return new TargetRecord(input.getModifiers(), input.getClassName(), javaGenerics, txGenerics, superInterfaces, constructors, fields, methods); + return new TargetRecord(input.getModifiers(), input.getClassName(), javaGenerics, txGenerics, superInterfaces, constructors, staticConstructor, 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); + return new TargetInterface(input.getModifiers(), input.getClassName(), javaGenerics, txGenerics, methods, superInterfaces, staticConstructor); + else return new TargetClass(input.getModifiers(), input.getClassName(), convert(input.getSuperClass(), generics.javaGenerics), javaGenerics, txGenerics, superInterfaces, constructors, staticConstructor, fields, methods); } private List convert(ParameterList input, GenerateGenerics generics) { diff --git a/src/main/java/de/dhbwstuttgart/target/generate/StatementToTargetExpression.java b/src/main/java/de/dhbwstuttgart/target/generate/StatementToTargetExpression.java index 59298379..880d02a3 100644 --- a/src/main/java/de/dhbwstuttgart/target/generate/StatementToTargetExpression.java +++ b/src/main/java/de/dhbwstuttgart/target/generate/StatementToTargetExpression.java @@ -134,7 +134,7 @@ public class StatementToTargetExpression implements ASTVisitor { @Override public void visit(FieldVar fieldVar) { - result = new TargetFieldVar(converter.convert(fieldVar.getType()), converter.convert(fieldVar.receiver.getType()), false, converter.convert(fieldVar.receiver), fieldVar.fieldVarName); + result = new TargetFieldVar(converter.convert(fieldVar.getType()), converter.convert(fieldVar.receiver.getType()), fieldVar.isStatic, converter.convert(fieldVar.receiver), fieldVar.fieldVarName); } @Override diff --git a/src/main/java/de/dhbwstuttgart/target/tree/TargetClass.java b/src/main/java/de/dhbwstuttgart/target/tree/TargetClass.java index ab68ca37..cf66c4e9 100644 --- a/src/main/java/de/dhbwstuttgart/target/tree/TargetClass.java +++ b/src/main/java/de/dhbwstuttgart/target/tree/TargetClass.java @@ -11,13 +11,13 @@ import java.util.List; import java.util.Set; public record TargetClass(int modifiers, JavaClassName qualifiedName, TargetType superType, Set generics, Set txGenerics, List implementingInterfaces, - List constructors, List fields, List methods) implements TargetStructure { + List constructors, TargetMethod staticConstructor, List fields, List methods) implements TargetStructure { public TargetClass(int modifiers, JavaClassName qualifiedName) { - this(modifiers, qualifiedName, TargetType.Object, new HashSet<>(), new HashSet<>(), new ArrayList<>(), new ArrayList<>(), new ArrayList<>(), new ArrayList<>()); + this(modifiers, qualifiedName, TargetType.Object, new HashSet<>(), new HashSet<>(), new ArrayList<>(), new ArrayList<>(), null, new ArrayList<>(), new ArrayList<>()); } public TargetClass(int modifiers, JavaClassName qualifiedName, List implementingInterfaces) { - this(modifiers, qualifiedName, TargetType.Object, new HashSet<>(), new HashSet<>(), implementingInterfaces, new ArrayList<>(), new ArrayList<>(), new ArrayList<>()); + this(modifiers, qualifiedName, TargetType.Object, new HashSet<>(), new HashSet<>(), implementingInterfaces, new ArrayList<>(), null, new ArrayList<>(), new ArrayList<>()); } public void addField(int access, TargetRefType type, String name) { diff --git a/src/main/java/de/dhbwstuttgart/target/tree/TargetInterface.java b/src/main/java/de/dhbwstuttgart/target/tree/TargetInterface.java index c5442cce..763636c5 100644 --- a/src/main/java/de/dhbwstuttgart/target/tree/TargetInterface.java +++ b/src/main/java/de/dhbwstuttgart/target/tree/TargetInterface.java @@ -6,7 +6,7 @@ import de.dhbwstuttgart.target.tree.type.TargetType; import java.util.List; import java.util.Set; -public record TargetInterface(int modifiers, JavaClassName qualifiedName, Set generics, Set txGenerics, List methods, List implementingInterfaces) implements TargetStructure { +public record TargetInterface(int modifiers, JavaClassName qualifiedName, Set generics, Set txGenerics, List methods, List implementingInterfaces, TargetMethod staticConstructor) implements TargetStructure { @Override public TargetType superType() { return null; diff --git a/src/main/java/de/dhbwstuttgart/target/tree/TargetRecord.java b/src/main/java/de/dhbwstuttgart/target/tree/TargetRecord.java index a6571002..976f8322 100644 --- a/src/main/java/de/dhbwstuttgart/target/tree/TargetRecord.java +++ b/src/main/java/de/dhbwstuttgart/target/tree/TargetRecord.java @@ -7,7 +7,7 @@ import de.dhbwstuttgart.target.tree.type.TargetType; import java.util.List; import java.util.Set; -public record TargetRecord(int modifiers, JavaClassName qualifiedName, Set generics, Set txGenerics, List implementingInterfaces, List constructors, List fields, List methods) implements TargetStructure { +public record TargetRecord(int modifiers, JavaClassName qualifiedName, Set generics, Set txGenerics, List implementingInterfaces, List constructors, TargetMethod staticConstructor, List fields, List methods) implements TargetStructure { public static final TargetType RECORD = new TargetRefType("java.lang.Record"); public TargetType superType() { diff --git a/src/main/java/de/dhbwstuttgart/target/tree/TargetStructure.java b/src/main/java/de/dhbwstuttgart/target/tree/TargetStructure.java index 4594920e..783bf86a 100644 --- a/src/main/java/de/dhbwstuttgart/target/tree/TargetStructure.java +++ b/src/main/java/de/dhbwstuttgart/target/tree/TargetStructure.java @@ -15,6 +15,9 @@ public interface TargetStructure { Set txGenerics(); List implementingInterfaces(); List constructors(); + + TargetMethod staticConstructor(); + List fields(); List methods(); diff --git a/src/main/java/de/dhbwstuttgart/typeinference/assumptions/FunNClass.java b/src/main/java/de/dhbwstuttgart/typeinference/assumptions/FunNClass.java index cf8fa897..48a07459 100644 --- a/src/main/java/de/dhbwstuttgart/typeinference/assumptions/FunNClass.java +++ b/src/main/java/de/dhbwstuttgart/typeinference/assumptions/FunNClass.java @@ -15,13 +15,14 @@ import de.dhbwstuttgart.syntaxtree.type.TypePlaceholder; import org.antlr.v4.runtime.Token; +import javax.swing.text.html.Option; import java.util.ArrayList; import java.util.List; import java.util.Optional; public class FunNClass extends ClassOrInterface { public FunNClass(List funNParams) { - super(0, new JavaClassName("Fun" + (funNParams.size() - 1)), new ArrayList<>(), Optional.empty() /* eingefuegt PL 2018-11-24 */, createMethods(funNParams), new ArrayList<>(), createGenerics(funNParams), ASTFactory.createObjectType(), true, new ArrayList<>(), new ArrayList<>(), new NullToken()); + super(0, new JavaClassName("Fun" + (funNParams.size() - 1)), new ArrayList<>(), Optional.empty(), Optional.empty() /* eingefuegt PL 2018-11-24 */, createMethods(funNParams), new ArrayList<>(), createGenerics(funNParams), ASTFactory.createObjectType(), true, new ArrayList<>(), new ArrayList<>(), new NullToken()); } diff --git a/src/main/java/de/dhbwstuttgart/typeinference/typeAlgo/TYPE.java b/src/main/java/de/dhbwstuttgart/typeinference/typeAlgo/TYPE.java index dba8f6c0..73a9e868 100644 --- a/src/main/java/de/dhbwstuttgart/typeinference/typeAlgo/TYPE.java +++ b/src/main/java/de/dhbwstuttgart/typeinference/typeAlgo/TYPE.java @@ -45,6 +45,10 @@ public class TYPE { if (cl.getfieldInitializations().isPresent()) { ret.addAll(getConstraintsConstructor(cl.getfieldInitializations().get(), info, cl)); } + if (cl.getStaticInitializer().isPresent()) { + ret.addAll(getConstraintsConstructor(cl.getStaticInitializer().get(), info, cl)); + } + return ret; } /* diff --git a/src/test/java/TestComplete.java b/src/test/java/TestComplete.java index 0d61e0ba..99619afc 100644 --- a/src/test/java/TestComplete.java +++ b/src/test/java/TestComplete.java @@ -719,6 +719,12 @@ public class TestComplete { var classFiles = generateClassFiles(new ByteArrayClassLoader(), "Interfaces.jav"); var clazz = classFiles.get("Interfaces"); var instance = clazz.getDeclaredConstructor().newInstance(); - System.out.println(Arrays.toString(clazz.getInterfaces())); + } + @Test + public void testStatic() throws Exception { + var classFiles = generateClassFiles(new ByteArrayClassLoader(), "Static.jav"); + var clazz = classFiles.get("Static"); + var m = clazz.getDeclaredMethod("m"); + assertEquals(m.invoke(null), 20); } } diff --git a/src/test/java/targetast/ASTToTypedTargetAST.java b/src/test/java/targetast/ASTToTypedTargetAST.java index d49b61a5..e3eb2276 100644 --- a/src/test/java/targetast/ASTToTypedTargetAST.java +++ b/src/test/java/targetast/ASTToTypedTargetAST.java @@ -8,17 +8,13 @@ import de.dhbwstuttgart.parser.scope.JavaClassName; import de.dhbwstuttgart.syntaxtree.*; import de.dhbwstuttgart.syntaxtree.type.RefType; import de.dhbwstuttgart.target.generate.ASTToTargetAST; -import de.dhbwstuttgart.target.tree.TargetClass; import de.dhbwstuttgart.target.tree.TargetStructure; import de.dhbwstuttgart.typeinference.result.ResultSet; import org.junit.Ignore; import org.junit.Test; import java.nio.file.Path; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Vector; +import java.util.*; import static org.junit.Assert.*; @@ -26,7 +22,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 ArrayList<>(), new NullToken()); + ClassOrInterface emptyClass = new ClassOrInterface(0, new JavaClassName("EmptyClass"), new ArrayList<>(), Optional.empty(), 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<>()); TargetStructure emptyTargetClass = new ASTToTargetAST(List.of(emptyResultSet)).convert(emptyClass); assert emptyTargetClass.getName().equals("EmptyClass");