From af5b23e31aa731758eadd292f097bc2350474543 Mon Sep 17 00:00:00 2001 From: JanUlrich Date: Sat, 14 Dec 2019 15:35:52 +0100 Subject: [PATCH 01/11] Use JavaClassName instead of Strings --- .../dhbwstuttgart/bytecode/BytecodeGen.java | 17 ++++++------ .../bytecode/BytecodeGenMethod.java | 27 ++++++++++--------- .../GeneratedGenericsFinder.java | 5 ++-- .../genericsGenerator/GenericsGenerator.java | 3 ++- .../GenericGenratorResultForSourceFile.java | 6 +++-- .../GenericsGeneratorResultForClass.java | 12 +++++---- .../de/dhbwstuttgart/core/JavaTXCompiler.java | 21 ++++++++------- .../parser/scope/JavaClassName.java | 13 ++++++++- .../typedeployment/TypeInsertFactory.java | 2 +- src/test/java/packages/Bytecode.java | 4 +-- vorgehen.md | 16 +++++++++++ 11 files changed, 82 insertions(+), 44 deletions(-) diff --git a/src/main/java/de/dhbwstuttgart/bytecode/BytecodeGen.java b/src/main/java/de/dhbwstuttgart/bytecode/BytecodeGen.java index 508bd520..e0602731 100644 --- a/src/main/java/de/dhbwstuttgart/bytecode/BytecodeGen.java +++ b/src/main/java/de/dhbwstuttgart/bytecode/BytecodeGen.java @@ -7,6 +7,7 @@ import java.util.Iterator; import java.util.List; import java.util.Optional; +import de.dhbwstuttgart.parser.scope.JavaClassName; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.FieldVisitor; import org.objectweb.asm.MethodVisitor; @@ -81,7 +82,7 @@ public class BytecodeGen implements ASTVisitor { String type; public static RefTypeOrTPHOrWildcardOrGeneric THISTYPE = null; - private String className; + private JavaClassName className; private String pkgName; private boolean isInterface; private Collection listOfResultSets; @@ -107,7 +108,7 @@ public class BytecodeGen implements ASTVisitor { HashMap methodParamsAndTypes = new HashMap<>(); byte[] bytecode; - HashMap classFiles; + HashMap classFiles; private final ArrayList methodNameAndParamsT = new ArrayList<>(); private final ArrayList fieldNameAndParamsT = new ArrayList<>(); @@ -119,7 +120,7 @@ public class BytecodeGen implements ASTVisitor { private Resolver resolver; - public BytecodeGen(HashMap classFiles, Collection listOfResultSets, List simplifyResultsForAllSourceFiles, SourceFile sf, + public BytecodeGen(HashMap classFiles, Collection listOfResultSets, List simplifyResultsForAllSourceFiles, SourceFile sf, String path) { this.classFiles = classFiles; this.listOfResultSets = listOfResultSets; @@ -135,7 +136,7 @@ public class BytecodeGen implements ASTVisitor { System.out.println("in Class: " + cl.getClassName().toString()); BytecodeGen classGen = new BytecodeGen(classFiles, listOfResultSets, simplifyResultsForAllSourceFiles, sf, path); cl.accept(classGen); - classGen.writeClass(cl.getClassName().toString()); + classGen.writeClass(cl.getClassName()); } } @@ -145,20 +146,20 @@ public class BytecodeGen implements ASTVisitor { * * @param name name of the class with which the bytecode is to be associated */ - private void writeClass(String name) { + private void writeClass(JavaClassName name) { bytecode = cw.toByteArray(); classFiles.put(name, bytecode); } - public HashMap getClassFiles() { + public HashMap getClassFiles() { return classFiles; } @Override public void visit(ClassOrInterface classOrInterface) { - className = classOrInterface.getClassName().toString(); + className = classOrInterface.getClassName(); cw.visitSource(className + ".jav", null); @@ -172,7 +173,7 @@ public class BytecodeGen implements ASTVisitor { // resultSet = listOfResultSets.get(0); boolean isVisited = false; List listOfResultSetsList = new ArrayList<>(listOfResultSets); - generatedGenerics = simplifyResultsForAllSourceFiles.stream().map(sr->sr.getSimplifyResultsByName(pkgName, className)).findFirst().get(); + generatedGenerics = simplifyResultsForAllSourceFiles.stream().map(sr->sr.getSimplifyResultsByName(className)).findFirst().get(); for (int i = 0; i < listOfResultSetsList.size(); i++) { //for (ResultSet rs : listOfResultSets) { superClass = classOrInterface.getSuperClass().acceptTV(new TypeToDescriptor()); diff --git a/src/main/java/de/dhbwstuttgart/bytecode/BytecodeGenMethod.java b/src/main/java/de/dhbwstuttgart/bytecode/BytecodeGenMethod.java index 46caa52b..9a485561 100644 --- a/src/main/java/de/dhbwstuttgart/bytecode/BytecodeGenMethod.java +++ b/src/main/java/de/dhbwstuttgart/bytecode/BytecodeGenMethod.java @@ -15,6 +15,7 @@ import java.util.List; import de.dhbwstuttgart.bytecode.utilities.*; import de.dhbwstuttgart.exceptions.NotImplementedException; +import de.dhbwstuttgart.parser.scope.JavaClassName; import de.dhbwstuttgart.syntaxtree.statement.*; import de.dhbwstuttgart.syntaxtree.statement.BinaryExpr.Operator; import de.dhbwstuttgart.syntaxtree.statement.UnaryExpr.Operation; @@ -45,7 +46,7 @@ public class BytecodeGenMethod implements StatementVisitor { private Method m; private MethodVisitor mv; private HashMap paramsAndLocals = new HashMap<>(); - private String className; + private JavaClassName className; private int lamCounter; private ClassWriter cw; private ResultSet resultSet; @@ -71,16 +72,16 @@ public class BytecodeGenMethod implements StatementVisitor { private boolean isRightSideALambda = false; private KindOfLambda kindOfLambda; - private HashMap classFiles; + private HashMap classFiles; private int constructorPos = 0; private ArrayList varsFunInterface = new ArrayList<>();; // generate bytecode for constructor - public BytecodeGenMethod(String className, String superClass,ResultSet resultSet, Method m, MethodVisitor mv, - HashMap paramsAndLocals, ClassWriter cw, HashMap genericsAndBoundsMethod, - HashMap genericsAndBounds, boolean isInterface, HashMap classFiles, - SourceFile sf,String path, Block block, int constructorPos) { + public BytecodeGenMethod(JavaClassName className, String superClass, ResultSet resultSet, Method m, MethodVisitor mv, + HashMap paramsAndLocals, ClassWriter cw, HashMap genericsAndBoundsMethod, + HashMap genericsAndBounds, boolean isInterface, HashMap classFiles, + SourceFile sf, String path, Block block, int constructorPos) { this.className = className; this.superClass = superClass; @@ -105,9 +106,9 @@ public class BytecodeGenMethod implements StatementVisitor { } - public BytecodeGenMethod(String className, String superClass,ResultSet resultSet, Method m, MethodVisitor mv, + public BytecodeGenMethod(JavaClassName className, String superClass,ResultSet resultSet, Method m, MethodVisitor mv, HashMap paramsAndLocals, ClassWriter cw, HashMap genericsAndBoundsMethod, - HashMap genericsAndBounds, boolean isInterface, HashMap classFiles, SourceFile sf,String path) { + HashMap genericsAndBounds, boolean isInterface, HashMap classFiles, SourceFile sf,String path) { this.className = className; this.superClass = superClass; @@ -129,8 +130,8 @@ public class BytecodeGenMethod implements StatementVisitor { } - public BytecodeGenMethod(String className, ClassWriter cw, LambdaExpression lambdaExpression, ArrayList usedVars, ResultSet resultSet, MethodVisitor mv, - int indexOfFirstParamLam, boolean isInterface, HashMap classFiles, String path, int lamCounter, SourceFile sf,HashMap genericsAndBoundsMethod, + public BytecodeGenMethod(JavaClassName className, ClassWriter cw, LambdaExpression lambdaExpression, ArrayList usedVars, ResultSet resultSet, MethodVisitor mv, + int indexOfFirstParamLam, boolean isInterface, HashMap classFiles, String path, int lamCounter, SourceFile sf,HashMap genericsAndBoundsMethod, HashMap genericsAndBounds) { this.className = className; this.cw = cw; @@ -622,7 +623,7 @@ public class BytecodeGenMethod implements StatementVisitor { } String newDesc = addUsedVarsToDesugaredMethodDescriptor(lamDesc); // first check if capturing lambda then invokestatic or invokespecial - Handle arg2 = new Handle(staticOrSpecial, this.className, desugaredMethodName, newDesc, false); + Handle arg2 = new Handle(staticOrSpecial, this.className.toString(), desugaredMethodName, newDesc, false); // Descriptor of functional interface methode SamMethod samMethod = new SamMethod(kindOfLambda.getArgumentList(), lambdaExpression.getType()); // Desc: (this/nothing)TargetType @@ -797,7 +798,7 @@ public class BytecodeGenMethod implements StatementVisitor { } if(methodRefl == null) { - boolean toCreate = !receiverName.equals(className) && helper.isInCurrPkg(clazz); + boolean toCreate = !receiverName.equals(className.toString()) && helper.isInCurrPkg(clazz); if(toCreate) { try { mDesc = helper.getDesc(clazz); @@ -832,7 +833,7 @@ public class BytecodeGenMethod implements StatementVisitor { System.out.println("Methodcall type : " + resultSet.resolveType(methodCall.getType()).resolvedType.acceptTV(new TypeToDescriptor())); List argListMethCall = new LinkedList<>(); String receiverRefl=""; - if(methodRefl == null && receiverName.equals(className)) { + if(methodRefl == null && receiverName.equals(className.toString())) { MethodFromMethodCall method = new MethodFromMethodCall(methodCall.arglist, methodCall.getType(), receiverName, genericsAndBoundsMethod, genericsAndBounds); mDesc = method.accept(new DescriptorToString(resultSet)); diff --git a/src/main/java/de/dhbwstuttgart/bytecode/genericsGenerator/GeneratedGenericsFinder.java b/src/main/java/de/dhbwstuttgart/bytecode/genericsGenerator/GeneratedGenericsFinder.java index 5e473ebe..ba55c4c7 100644 --- a/src/main/java/de/dhbwstuttgart/bytecode/genericsGenerator/GeneratedGenericsFinder.java +++ b/src/main/java/de/dhbwstuttgart/bytecode/genericsGenerator/GeneratedGenericsFinder.java @@ -16,6 +16,7 @@ import de.dhbwstuttgart.bytecode.utilities.MethodAndTPH; import de.dhbwstuttgart.bytecode.utilities.MethodUtility; import de.dhbwstuttgart.bytecode.utilities.Resolver; import de.dhbwstuttgart.parser.SyntaxTreeGenerator.AssignToLocal; +import de.dhbwstuttgart.parser.scope.JavaClassName; import de.dhbwstuttgart.syntaxtree.ASTVisitor; import de.dhbwstuttgart.syntaxtree.ClassOrInterface; import de.dhbwstuttgart.syntaxtree.Constructor; @@ -75,7 +76,7 @@ public class GeneratedGenericsFinder implements ASTVisitor { private final List methodNameAndParamsT = new ArrayList<>(); private String pkgName; - private String className; + private JavaClassName className; private Resolver resolver; /** @@ -117,7 +118,7 @@ public class GeneratedGenericsFinder implements ASTVisitor { */ @Override public void visit(ClassOrInterface classOrInterface) { - className = classOrInterface.getClassName().toString(); + className = classOrInterface.getClassName(); List listOfResultSetsList = new ArrayList<>(listOfResultSets); boolean isVisited = false; diff --git a/src/main/java/de/dhbwstuttgart/bytecode/genericsGenerator/GenericsGenerator.java b/src/main/java/de/dhbwstuttgart/bytecode/genericsGenerator/GenericsGenerator.java index a541025c..8e5bd481 100644 --- a/src/main/java/de/dhbwstuttgart/bytecode/genericsGenerator/GenericsGenerator.java +++ b/src/main/java/de/dhbwstuttgart/bytecode/genericsGenerator/GenericsGenerator.java @@ -12,6 +12,7 @@ import java.util.Set; import java.util.stream.Collectors; import de.dhbwstuttgart.bytecode.genericsGeneratorTypes.*; +import de.dhbwstuttgart.parser.scope.JavaClassName; import org.objectweb.asm.Type; import de.dhbwstuttgart.bytecode.TPHExtractor; @@ -30,7 +31,7 @@ public class GenericsGenerator { class constraints: tphClass < tphMeth1, tphMeth1 < tphMeth2, tphMeth2 < Object */ - public static GenericsGeneratorResultForClass generateConstraints(final String className, final TPHExtractor tphExtractor, + public static GenericsGeneratorResultForClass generateConstraints(final JavaClassName className, final TPHExtractor tphExtractor, final List tphsClass, final ConstraintsSimplierResult simplifiedConstraints) { List classConstraints = generateConstraintsForClass(tphExtractor, diff --git a/src/main/java/de/dhbwstuttgart/bytecode/genericsGeneratorTypes/GenericGenratorResultForSourceFile.java b/src/main/java/de/dhbwstuttgart/bytecode/genericsGeneratorTypes/GenericGenratorResultForSourceFile.java index 85d0bcbf..f0d11473 100644 --- a/src/main/java/de/dhbwstuttgart/bytecode/genericsGeneratorTypes/GenericGenratorResultForSourceFile.java +++ b/src/main/java/de/dhbwstuttgart/bytecode/genericsGeneratorTypes/GenericGenratorResultForSourceFile.java @@ -3,6 +3,8 @@ */ package de.dhbwstuttgart.bytecode.genericsGeneratorTypes; +import de.dhbwstuttgart.parser.scope.JavaClassName; + import java.util.ArrayList; import java.util.List; import java.util.NoSuchElementException; @@ -37,9 +39,9 @@ public class GenericGenratorResultForSourceFile { genericGeneratorResultForAllClasses.add(sResClass); } - public GenericsGeneratorResultForClass getSimplifyResultsByName(String pkgName, String name) { + public GenericsGeneratorResultForClass getSimplifyResultsByName(JavaClassName name) { - if (this.pkgName.equals(pkgName)) { + if (this.pkgName.equals(name.getPackageName())) { return genericGeneratorResultForAllClasses.stream() .filter(sr -> sr.getClassName().equals(name)) .findAny() diff --git a/src/main/java/de/dhbwstuttgart/bytecode/genericsGeneratorTypes/GenericsGeneratorResultForClass.java b/src/main/java/de/dhbwstuttgart/bytecode/genericsGeneratorTypes/GenericsGeneratorResultForClass.java index d6532ecb..eaeb1f3a 100644 --- a/src/main/java/de/dhbwstuttgart/bytecode/genericsGeneratorTypes/GenericsGeneratorResultForClass.java +++ b/src/main/java/de/dhbwstuttgart/bytecode/genericsGeneratorTypes/GenericsGeneratorResultForClass.java @@ -3,6 +3,8 @@ */ package de.dhbwstuttgart.bytecode.genericsGeneratorTypes; +import de.dhbwstuttgart.parser.scope.JavaClassName; + import java.util.Collections; import java.util.List; @@ -11,11 +13,11 @@ import java.util.List; * */ public class GenericsGeneratorResultForClass { - private final String className; + private final JavaClassName className; private final List classConstraints; private final GenericGeneratorResultsForAllMethods methodsAndTheirConstraints; - public GenericsGeneratorResultForClass(String className) { + public GenericsGeneratorResultForClass(JavaClassName className) { this(className, Collections.emptyList(), new GenericGeneratorResultsForAllMethods()); } /** @@ -23,8 +25,8 @@ public class GenericsGeneratorResultForClass { * @param classConstraints * @param methodsAndTheirConstraints */ - public GenericsGeneratorResultForClass(String className, List classConstraints, - GenericGeneratorResultsForAllMethods methodsAndTheirConstraints) { + public GenericsGeneratorResultForClass(JavaClassName className, List classConstraints, + GenericGeneratorResultsForAllMethods methodsAndTheirConstraints) { this.className = className; this.classConstraints = classConstraints; this.methodsAndTheirConstraints = methodsAndTheirConstraints; @@ -33,7 +35,7 @@ public class GenericsGeneratorResultForClass { /** * @return the className */ - public String getClassName() { + public JavaClassName getClassName() { return className; } diff --git a/src/main/java/de/dhbwstuttgart/core/JavaTXCompiler.java b/src/main/java/de/dhbwstuttgart/core/JavaTXCompiler.java index 5f107ed0..3c234175 100644 --- a/src/main/java/de/dhbwstuttgart/core/JavaTXCompiler.java +++ b/src/main/java/de/dhbwstuttgart/core/JavaTXCompiler.java @@ -714,7 +714,7 @@ public class JavaTXCompiler { return ret; } - public void generateBytecodForFile(String path, HashMap classFiles, SourceFile sf, + public void generateBytecodForFile(String path, HashMap classFiles, SourceFile sf, List typeinferenceResult) throws IOException { try { List genericResults = getGeneratedGenericResultsForAllSourceFiles(typeinferenceResult); @@ -753,7 +753,9 @@ public class JavaTXCompiler { return result; } - // um pfad erweitern + /** + * @param path - can be null, then class file output is in the same directory as the parsed source files + */ public void generateBytecode(String path) throws ClassNotFoundException, IOException, BytecodeGeneratorError { List typeinferenceResult = this.typeInference(); List simplifyResultsForAllSourceFiles = getGeneratedGenericResultsForAllSourceFiles( @@ -770,27 +772,28 @@ public class JavaTXCompiler { public void generateBytecode(String path, List typeinferenceResult, List simplifyResultsForAllSourceFiles) throws IOException { for (File f : sourceFiles.keySet()) { - HashMap classFiles = new HashMap<>(); + HashMap classFiles = new HashMap<>(); SourceFile sf = sourceFiles.get(f); BytecodeGen bytecodeGen = new BytecodeGen(classFiles, typeinferenceResult, simplifyResultsForAllSourceFiles, sf, path); bytecodeGen.visit(sf); - String packagePath = sf.getPkgName().replace(".","/"); if(path == null){ - path = f.getPath(); + path = f.getParent(); //Set path to path of the parsed .jav file + }else{ + path += sf.getPkgName().replace(".","/"); //add package path to root path } - writeClassFile(bytecodeGen.getClassFiles(), path + packagePath); + writeClassFile(bytecodeGen.getClassFiles(), path); } } - private void writeClassFile(HashMap classFiles, String path) throws IOException { + private void writeClassFile(HashMap classFiles, String path) throws IOException { FileOutputStream output; - for (String name : classFiles.keySet()) { + for (JavaClassName name : classFiles.keySet()) { byte[] bytecode = classFiles.get(name); System.out.println("generating " + name + ".class file ..."); // output = new FileOutputStream(new File(System.getProperty("user.dir") + // "/testBytecode/generatedBC/" +name+".class")); - output = new FileOutputStream(new File(path + name + ".class")); + output = new FileOutputStream(new File(path + File.separator + name.getClassName() + ".class")); output.write(bytecode); output.close(); System.out.println(name + ".class file generated"); diff --git a/src/main/java/de/dhbwstuttgart/parser/scope/JavaClassName.java b/src/main/java/de/dhbwstuttgart/parser/scope/JavaClassName.java index b87ff719..534d0916 100644 --- a/src/main/java/de/dhbwstuttgart/parser/scope/JavaClassName.java +++ b/src/main/java/de/dhbwstuttgart/parser/scope/JavaClassName.java @@ -84,7 +84,15 @@ public class JavaClassName { @Override public String toString() { - return (packageName!=null ? packageName.toString() : "") + name; + return (packageName!=null ? packageName.toString() + "." : "") + name; + } + + public String getPackageName() { + return (packageName!=null ? packageName.toString() : ""); + } + + public String getClassName(){ + return name; } } @@ -130,6 +138,9 @@ class PackageName{ String ret = ""; if(names == null)return ""; for(String n : names)ret+=n+"."; + if (ret != null && ret.length() > 0 && ret.charAt(ret.length() - 1) == '.') { + ret = ret.substring(0, ret.length() - 1); + } return ret; } } diff --git a/src/main/java/de/dhbwstuttgart/typedeployment/TypeInsertFactory.java b/src/main/java/de/dhbwstuttgart/typedeployment/TypeInsertFactory.java index 44bfd2ff..ebef5263 100644 --- a/src/main/java/de/dhbwstuttgart/typedeployment/TypeInsertFactory.java +++ b/src/main/java/de/dhbwstuttgart/typedeployment/TypeInsertFactory.java @@ -47,7 +47,7 @@ public class TypeInsertFactory { new TypeToInsertString(resolvedType.resolvedType).insert); List simplifyResults = JavaTXCompiler.INSTANCE.getGeneratedGenericResultsForAllSourceFiles(newResults); for (GenericGenratorResultForSourceFile simplifyResultsEntries : simplifyResults) { - GenericsGeneratorResultForClass genericResultsForClass = simplifyResultsEntries.getSimplifyResultsByName("", cl.getClassName().toString()); + GenericsGeneratorResultForClass genericResultsForClass = simplifyResultsEntries.getSimplifyResultsByName(cl.getClassName()); return new TypeInsert(insertPoint, createGenericInsert(genericResultsForClass, cl, m, resultSet, offset), resolvedType.getResultPair()); } diff --git a/src/test/java/packages/Bytecode.java b/src/test/java/packages/Bytecode.java index f02c83fa..1f7854c1 100644 --- a/src/test/java/packages/Bytecode.java +++ b/src/test/java/packages/Bytecode.java @@ -14,12 +14,12 @@ public class Bytecode extends TestCase { public void testSetPackageNameInBytecode() throws IOException, ClassNotFoundException { JavaTXCompiler compiler = new JavaTXCompiler(new File(rootDirectory+"packageNameTest.jav")); compiler.typeInference(); - File f = new File(rootDirectory + "Test.class"); + File f = new File(rootDirectory + "TestClass.class"); if(f.exists() && !f.isDirectory()) { f.delete(); } compiler.generateBytecode(null); - f = new File(rootDirectory + "Test.class"); + f = new File(rootDirectory + "TestClass.class"); assertTrue(f.exists()); } } diff --git a/vorgehen.md b/vorgehen.md index 61b62c4f..f6a3f169 100644 --- a/vorgehen.md +++ b/vorgehen.md @@ -28,3 +28,19 @@ * Optional * damit lässt sich ein andere ort zur Ausgabe der Class-files bestimmen +# Tasks +## Class files in richtigen Ordner legen ## +* Wenn Pfad übergeben, dann in Pfad + packageName +* Ohne Pfad, direkt neben die Source File legen +* wenn Source File nicht in richtigem Ordner -> Warnung ausgeben + +## Class files einlesen +* Wenn Classpath übergeben + * Suchen in Classpath + packageName +* Wenn nichts übergeben + * dann currentDirectory + packageName +* Für die Tests muss korrekter Classpath gesetzt werden + +## Class files mit packageNamen versehen +* In die Class file muss noch der korrekte name geschrieben werden + * kann möglicherweise ASM From a3b4ea9b1cc58805be862c379ccc67f426a8f402 Mon Sep 17 00:00:00 2001 From: JanUlrich Date: Sat, 14 Dec 2019 17:50:23 +0100 Subject: [PATCH 02/11] [Bytecde] Generate new directory if given output path doesnt exist yet --- .../java/de/dhbwstuttgart/core/JavaTXCompiler.java | 4 +++- src/test/java/packages/Bytecode.java | 13 +++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/main/java/de/dhbwstuttgart/core/JavaTXCompiler.java b/src/main/java/de/dhbwstuttgart/core/JavaTXCompiler.java index 3c234175..b1bb04ca 100644 --- a/src/main/java/de/dhbwstuttgart/core/JavaTXCompiler.java +++ b/src/main/java/de/dhbwstuttgart/core/JavaTXCompiler.java @@ -793,7 +793,9 @@ public class JavaTXCompiler { System.out.println("generating " + name + ".class file ..."); // output = new FileOutputStream(new File(System.getProperty("user.dir") + // "/testBytecode/generatedBC/" +name+".class")); - output = new FileOutputStream(new File(path + File.separator + name.getClassName() + ".class")); + File outputFile = new File(path + File.separator + name.getClassName() + ".class"); + outputFile.getParentFile().mkdirs(); + output = new FileOutputStream(outputFile); output.write(bytecode); output.close(); System.out.println(name + ".class file generated"); diff --git a/src/test/java/packages/Bytecode.java b/src/test/java/packages/Bytecode.java index 1f7854c1..ece46ac8 100644 --- a/src/test/java/packages/Bytecode.java +++ b/src/test/java/packages/Bytecode.java @@ -22,4 +22,17 @@ public class Bytecode extends TestCase { f = new File(rootDirectory + "TestClass.class"); assertTrue(f.exists()); } + + @Test + public void testSetPackageNameInBytecodeAndOutputFolder() throws IOException, ClassNotFoundException { + JavaTXCompiler compiler = new JavaTXCompiler(new File(rootDirectory+"packageNameTest.jav")); + compiler.typeInference(); + File f = new File(rootDirectory + "output/de/test/TestClass.class"); + if(f.exists() && !f.isDirectory()) { + f.delete(); + } + compiler.generateBytecode(rootDirectory + "output/"); + f = new File(rootDirectory + "output/de/test/TestClass.class"); + assertTrue(f.exists()); + } } From c82abcaae5448b7d26d76afa32458cb3191c35e7 Mon Sep 17 00:00:00 2001 From: JanUlrich Date: Sun, 15 Dec 2019 14:49:19 +0100 Subject: [PATCH 03/11] Generate Package names in .class files --- .../dhbwstuttgart/bytecode/BytecodeGen.java | 4 +-- .../bytecode/BytecodeGenMethod.java | 6 ++-- src/test/java/packages/Bytecode.java | 32 +++++++++++++------ src/test/java/packages/ParsePackageName.java | 2 +- .../typeinference/JavaTXCompilerTest.java | 4 +++ src/test/resources/javFiles/Import.jav | 2 +- .../packageTest/de/test/TestClass.jav | 3 ++ .../packageTest/de/test/packageNameTest.jav | 3 -- vorgehen.md | 7 ++++ 9 files changed, 43 insertions(+), 20 deletions(-) create mode 100644 src/test/resources/javFiles/packageTest/de/test/TestClass.jav delete mode 100644 src/test/resources/javFiles/packageTest/de/test/packageNameTest.jav diff --git a/src/main/java/de/dhbwstuttgart/bytecode/BytecodeGen.java b/src/main/java/de/dhbwstuttgart/bytecode/BytecodeGen.java index e0602731..fff65180 100644 --- a/src/main/java/de/dhbwstuttgart/bytecode/BytecodeGen.java +++ b/src/main/java/de/dhbwstuttgart/bytecode/BytecodeGen.java @@ -161,7 +161,7 @@ public class BytecodeGen implements ASTVisitor { className = classOrInterface.getClassName(); - cw.visitSource(className + ".jav", null); + cw.visitSource(className.getClassName() + ".jav", null); isInterface = (classOrInterface.getModifiers() & 512) == 512; @@ -200,7 +200,7 @@ public class BytecodeGen implements ASTVisitor { System.out.println("Signature: => " + sig); } - cw.visit(Opcodes.V1_8, acc, classOrInterface.getClassName().toString(), sig, + cw.visit(Opcodes.V1_8, acc, classOrInterface.getClassName().toString().replace(".", "/"), sig, classOrInterface.getSuperClass().acceptTV(new TypeToDescriptor()), null); isVisited = true; diff --git a/src/main/java/de/dhbwstuttgart/bytecode/BytecodeGenMethod.java b/src/main/java/de/dhbwstuttgart/bytecode/BytecodeGenMethod.java index 9a485561..04f895fe 100644 --- a/src/main/java/de/dhbwstuttgart/bytecode/BytecodeGenMethod.java +++ b/src/main/java/de/dhbwstuttgart/bytecode/BytecodeGenMethod.java @@ -623,7 +623,7 @@ public class BytecodeGenMethod implements StatementVisitor { } String newDesc = addUsedVarsToDesugaredMethodDescriptor(lamDesc); // first check if capturing lambda then invokestatic or invokespecial - Handle arg2 = new Handle(staticOrSpecial, this.className.toString(), desugaredMethodName, newDesc, false); + Handle arg2 = new Handle(staticOrSpecial, this.className.getClassName(), desugaredMethodName, newDesc, false); // Descriptor of functional interface methode SamMethod samMethod = new SamMethod(kindOfLambda.getArgumentList(), lambdaExpression.getType()); // Desc: (this/nothing)TargetType @@ -798,7 +798,7 @@ public class BytecodeGenMethod implements StatementVisitor { } if(methodRefl == null) { - boolean toCreate = !receiverName.equals(className.toString()) && helper.isInCurrPkg(clazz); + boolean toCreate = !receiverName.equals(className.getClassName()) && helper.isInCurrPkg(clazz); if(toCreate) { try { mDesc = helper.getDesc(clazz); @@ -833,7 +833,7 @@ public class BytecodeGenMethod implements StatementVisitor { System.out.println("Methodcall type : " + resultSet.resolveType(methodCall.getType()).resolvedType.acceptTV(new TypeToDescriptor())); List argListMethCall = new LinkedList<>(); String receiverRefl=""; - if(methodRefl == null && receiverName.equals(className.toString())) { + if(methodRefl == null && receiverName.equals(className.getClassName())) { MethodFromMethodCall method = new MethodFromMethodCall(methodCall.arglist, methodCall.getType(), receiverName, genericsAndBoundsMethod, genericsAndBounds); mDesc = method.accept(new DescriptorToString(resultSet)); diff --git a/src/test/java/packages/Bytecode.java b/src/test/java/packages/Bytecode.java index ece46ac8..7a5c4c25 100644 --- a/src/test/java/packages/Bytecode.java +++ b/src/test/java/packages/Bytecode.java @@ -6,33 +6,45 @@ import org.junit.Test; import java.io.File; import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.net.URL; +import java.net.URLClassLoader; public class Bytecode extends TestCase { - public static final String rootDirectory = System.getProperty("user.dir")+"/src/test/resources/javFiles/packageTest/de/test/"; + public static final String rootDirectory = System.getProperty("user.dir")+"/src/test/resources/javFiles/packageTest/"; @Test - public void testSetPackageNameInBytecode() throws IOException, ClassNotFoundException { - JavaTXCompiler compiler = new JavaTXCompiler(new File(rootDirectory+"packageNameTest.jav")); + public void testSetPackageNameInBytecode() throws Exception { + JavaTXCompiler compiler = new JavaTXCompiler(new File(rootDirectory+"de/test/TestClass.jav")); compiler.typeInference(); - File f = new File(rootDirectory + "TestClass.class"); + File f = new File(rootDirectory + "de/test/TestClass.class"); if(f.exists() && !f.isDirectory()) { f.delete(); } compiler.generateBytecode(null); - f = new File(rootDirectory + "TestClass.class"); + f = new File(rootDirectory + "de/test/TestClass.class"); assertTrue(f.exists()); + + + URLClassLoader loader = new URLClassLoader(new URL[]{new URL("file://" + rootDirectory)}); + Class classToTest = loader.loadClass("de.test.TestClass"); + Object instanceOfClass = classToTest.getDeclaredConstructor().newInstance(); } @Test - public void testSetPackageNameInBytecodeAndOutputFolder() throws IOException, ClassNotFoundException { - JavaTXCompiler compiler = new JavaTXCompiler(new File(rootDirectory+"packageNameTest.jav")); + public void testSetPackageNameInBytecodeAndOutputFolder() throws Exception { + JavaTXCompiler compiler = new JavaTXCompiler(new File(rootDirectory+"de/test/TestClass.jav")); compiler.typeInference(); - File f = new File(rootDirectory + "output/de/test/TestClass.class"); + File f = new File(rootDirectory + "de/test/output/de/test/TestClass.class"); if(f.exists() && !f.isDirectory()) { f.delete(); } - compiler.generateBytecode(rootDirectory + "output/"); - f = new File(rootDirectory + "output/de/test/TestClass.class"); + compiler.generateBytecode(rootDirectory + "de/test/output/"); + f = new File(rootDirectory + "de/test/output/de/test/TestClass.class"); assertTrue(f.exists()); + + URLClassLoader loader = new URLClassLoader(new URL[]{new URL("file://" + rootDirectory + "de/test/output/")}); + Class classToTest = loader.loadClass("de.test.TestClass"); + Object instanceOfClass = classToTest.getDeclaredConstructor().newInstance(); } } diff --git a/src/test/java/packages/ParsePackageName.java b/src/test/java/packages/ParsePackageName.java index b54cf90e..9dc0ea9a 100644 --- a/src/test/java/packages/ParsePackageName.java +++ b/src/test/java/packages/ParsePackageName.java @@ -12,7 +12,7 @@ public class ParsePackageName { public static final String rootDirectory = System.getProperty("user.dir")+"/src/test/resources/javFiles/packageTest/de/test/"; @Test public void parsePackage() throws IOException, ClassNotFoundException { - JavaTXCompiler compiler = new JavaTXCompiler(new File(rootDirectory+"packageNameTest.jav")); + JavaTXCompiler compiler = new JavaTXCompiler(new File(rootDirectory+"TestClass.jav")); for(File f : compiler.sourceFiles.keySet()){ SourceFile sf = compiler.sourceFiles.get(f); assert sf.getPkgName().equals("de.test"); diff --git a/src/test/java/typeinference/JavaTXCompilerTest.java b/src/test/java/typeinference/JavaTXCompilerTest.java index 87ae477d..ac724771 100644 --- a/src/test/java/typeinference/JavaTXCompilerTest.java +++ b/src/test/java/typeinference/JavaTXCompilerTest.java @@ -28,6 +28,10 @@ public class JavaTXCompilerTest { execute(new File(rootDirectory+"fc.jav")); } @Test + public void importTest() throws IOException, ClassNotFoundException { + execute(new File(rootDirectory+"Import.jav")); + } + @Test public void lambda() throws IOException, ClassNotFoundException { execute(new File(rootDirectory+"Lambda.jav")); } diff --git a/src/test/resources/javFiles/Import.jav b/src/test/resources/javFiles/Import.jav index c48082ba..2fc3a8b3 100644 --- a/src/test/resources/javFiles/Import.jav +++ b/src/test/resources/javFiles/Import.jav @@ -2,7 +2,7 @@ import java.util.Vector; class Import { void methode(){ - Vector v; + var v; v.add(v); } } \ No newline at end of file diff --git a/src/test/resources/javFiles/packageTest/de/test/TestClass.jav b/src/test/resources/javFiles/packageTest/de/test/TestClass.jav new file mode 100644 index 00000000..6681b36a --- /dev/null +++ b/src/test/resources/javFiles/packageTest/de/test/TestClass.jav @@ -0,0 +1,3 @@ +package de.test; + +public class TestClass{} \ No newline at end of file diff --git a/src/test/resources/javFiles/packageTest/de/test/packageNameTest.jav b/src/test/resources/javFiles/packageTest/de/test/packageNameTest.jav deleted file mode 100644 index ad5b9f63..00000000 --- a/src/test/resources/javFiles/packageTest/de/test/packageNameTest.jav +++ /dev/null @@ -1,3 +0,0 @@ -package de.test; - -class TestClass{} \ No newline at end of file diff --git a/vorgehen.md b/vorgehen.md index f6a3f169..834c49e7 100644 --- a/vorgehen.md +++ b/vorgehen.md @@ -34,6 +34,10 @@ * Ohne Pfad, direkt neben die Source File legen * wenn Source File nicht in richtigem Ordner -> Warnung ausgeben +### Stand ### +* Beinahe abgeschlossen +* TODO: Tests schreiben + ## Class files einlesen * Wenn Classpath übergeben * Suchen in Classpath + packageName @@ -41,6 +45,9 @@ * dann currentDirectory + packageName * Für die Tests muss korrekter Classpath gesetzt werden +### Stand ### +TODO + ## Class files mit packageNamen versehen * In die Class file muss noch der korrekte name geschrieben werden * kann möglicherweise ASM From bb75fca0d71273df971910da362eff6807afdd39 Mon Sep 17 00:00:00 2001 From: JanUlrich Date: Sun, 15 Dec 2019 14:57:03 +0100 Subject: [PATCH 04/11] Add ImportTest --- src/test/java/packages/ImportTest.java | 44 +++++++++++++++++++ .../packageTest/de/test/ImportTest.jav | 9 ++++ .../javFiles/packageTest/de/test/ToImport.jav | 4 ++ 3 files changed, 57 insertions(+) create mode 100644 src/test/java/packages/ImportTest.java create mode 100644 src/test/resources/javFiles/packageTest/de/test/ImportTest.jav create mode 100644 src/test/resources/javFiles/packageTest/de/test/ToImport.jav diff --git a/src/test/java/packages/ImportTest.java b/src/test/java/packages/ImportTest.java new file mode 100644 index 00000000..a6fbc075 --- /dev/null +++ b/src/test/java/packages/ImportTest.java @@ -0,0 +1,44 @@ +package packages; + +import de.dhbwstuttgart.core.JavaTXCompiler; +import junit.framework.TestCase; +import org.junit.Before; +import org.junit.Test; + +import java.io.File; +import java.io.IOException; + +public class ImportTest extends TestCase { + + public static final String rootDirectory = System.getProperty("user.dir")+"/src/test/resources/javFiles/packageTest/de/test/"; + + + public ImportTest() throws ClassNotFoundException, IOException { + /* + Generate ToImport class in rootDirectory and in output-Directory + */ + JavaTXCompiler compiler = new JavaTXCompiler(new File(rootDirectory+"ToImport.jav")); + compiler.typeInference(); + compiler.generateBytecode(rootDirectory + "output/"); + File f = new File(rootDirectory + "output/de/test/ToImport.class"); + assertTrue(f.exists()); + compiler = new JavaTXCompiler(new File(rootDirectory+"ToImport.jav")); + compiler.typeInference(); + compiler.generateBytecode(null); + f = new File(rootDirectory + "output/de/test/ToImport.class"); + assertTrue(f.exists()); + } + + @Test + public void testSetPackageNameInBytecodeAndOutputFolder() throws IOException, ClassNotFoundException { + JavaTXCompiler compiler = new JavaTXCompiler(new File(rootDirectory+"ImportTest.jav")); + compiler.typeInference(); + File f = new File(rootDirectory + "output/de/test/ImportTest.class"); + if(f.exists() && !f.isDirectory()) { + f.delete(); + } + compiler.generateBytecode(rootDirectory + "output/"); + f = new File(rootDirectory + "output/de/test/ImportTest.class"); + assertTrue(f.exists()); + } +} diff --git a/src/test/resources/javFiles/packageTest/de/test/ImportTest.jav b/src/test/resources/javFiles/packageTest/de/test/ImportTest.jav new file mode 100644 index 00000000..58b6fc0b --- /dev/null +++ b/src/test/resources/javFiles/packageTest/de/test/ImportTest.jav @@ -0,0 +1,9 @@ +package de.test; + +import de.test.ToImport; + +class ImportTest{ + void methode(){ + new ToImport(); + } +} \ No newline at end of file diff --git a/src/test/resources/javFiles/packageTest/de/test/ToImport.jav b/src/test/resources/javFiles/packageTest/de/test/ToImport.jav new file mode 100644 index 00000000..3afdba54 --- /dev/null +++ b/src/test/resources/javFiles/packageTest/de/test/ToImport.jav @@ -0,0 +1,4 @@ +package de.test; + +class ToImport{ +} \ No newline at end of file From 74622550c26f33e3a2111ed4f381f38bdb9b02fd Mon Sep 17 00:00:00 2001 From: JanUlrich Date: Sun, 15 Dec 2019 21:58:29 +0100 Subject: [PATCH 05/11] Add Logfiles Directory, but ignore all files inside it --- .gitignore | 3 +++ logFiles/.gitkeep | 0 2 files changed, 3 insertions(+) create mode 100644 logFiles/.gitkeep diff --git a/.gitignore b/.gitignore index a897efd8..fe551a27 100644 --- a/.gitignore +++ b/.gitignore @@ -23,3 +23,6 @@ bin # manually/ + +logFiles/** +!logFiles/.gitkeep diff --git a/logFiles/.gitkeep b/logFiles/.gitkeep new file mode 100644 index 00000000..e69de29b From afd2c21ca8f9b7aaef31364cb12c82d9d0f58c9a Mon Sep 17 00:00:00 2001 From: JanUlrich Date: Mon, 16 Dec 2019 00:54:00 +0100 Subject: [PATCH 06/11] Add classPath option to JavaTXCompiler and parse with URLClassLoader --- .../de/dhbwstuttgart/core/JavaTXCompiler.java | 35 +++++++++++++------ .../environment/CompilationEnvironment.java | 4 +-- .../StatementGenerator.java | 18 ++++++++-- .../SyntaxTreeGenerator.java | 5 +-- .../parser/scope/GatherNames.java | 14 ++++---- src/test/java/packages/ImportTest.java | 6 +++- vorgehen.md | 10 ++++-- 7 files changed, 63 insertions(+), 29 deletions(-) diff --git a/src/main/java/de/dhbwstuttgart/core/JavaTXCompiler.java b/src/main/java/de/dhbwstuttgart/core/JavaTXCompiler.java index b1bb04ca..61f90e42 100644 --- a/src/main/java/de/dhbwstuttgart/core/JavaTXCompiler.java +++ b/src/main/java/de/dhbwstuttgart/core/JavaTXCompiler.java @@ -1,6 +1,7 @@ //PL 2018-12-19: typeInferenceOld nach typeInference uebertragen package de.dhbwstuttgart.core; +import com.google.common.collect.Lists; import de.dhbwstuttgart.bytecode.BytecodeGen; import de.dhbwstuttgart.bytecode.Exception.BytecodeGeneratorError; import de.dhbwstuttgart.bytecode.genericsGenerator.GeneratedGenericsFinder; @@ -41,6 +42,8 @@ import java.io.FileOutputStream; import java.io.FileWriter; import java.io.IOException; import java.io.Writer; +import java.net.URL; +import java.net.URLClassLoader; import java.util.*; import java.util.function.Function; import java.util.stream.Collectors; @@ -50,24 +53,34 @@ public class JavaTXCompiler { public static JavaTXCompiler INSTANCE; final CompilationEnvironment environment; - Boolean resultmodel = true; + Boolean resultmodel = true; public final Map sourceFiles = new HashMap<>(); Boolean log = true; //gibt an ob ein Log-File nach System.getProperty("user.dir")+"src/test/java/logFiles" geschrieben werden soll? public volatile UnifyTaskModel usedTasks = new UnifyTaskModel(); - - public JavaTXCompiler(File sourceFile) throws IOException, ClassNotFoundException { - this(Arrays.asList(sourceFile)); - INSTANCE = this; - } + private final ClassLoader classLoader; + + public JavaTXCompiler(File sourceFile) throws IOException, ClassNotFoundException { + this(Arrays.asList(sourceFile), null); + INSTANCE = this; + } public JavaTXCompiler(File sourceFile, Boolean log) throws IOException, ClassNotFoundException { this(sourceFile); this.log = log; INSTANCE = this; } - - public JavaTXCompiler(List sources) throws IOException, ClassNotFoundException { - environment = new CompilationEnvironment(sources); + + public JavaTXCompiler(List sourceFiles) throws IOException, ClassNotFoundException { + this(sourceFiles, null); + INSTANCE = this; + } + public JavaTXCompiler(List sources, List contextPath) throws IOException, ClassNotFoundException { + if(contextPath == null || contextPath.isEmpty()){ + //When no contextPaths are given, the working directory is the sources root + contextPath = Lists.newArrayList(new URL("file://" + System.getProperty("user.dir"))); + } + classLoader = new URLClassLoader(contextPath.toArray(new URL[0]), ClassLoader.getSystemClassLoader()); + environment = new CompilationEnvironment(sources); for (File s : sources) { sourceFiles.put(s, parse(s)); } @@ -708,9 +721,9 @@ public class JavaTXCompiler { private SourceFile parse(File sourceFile) throws IOException, java.lang.ClassNotFoundException { CompilationUnitContext tree = JavaTXParser.parse(sourceFile); - SyntaxTreeGenerator generator = new SyntaxTreeGenerator(environment.getRegistry(sourceFile), + SyntaxTreeGenerator generator = new SyntaxTreeGenerator(environment.getRegistry(sourceFile, classLoader), new GenericsRegistry(null)); - SourceFile ret = generator.convert(tree, environment.packageCrawler); + SourceFile ret = generator.convert(tree, environment.packageCrawler, classLoader); return ret; } diff --git a/src/main/java/de/dhbwstuttgart/environment/CompilationEnvironment.java b/src/main/java/de/dhbwstuttgart/environment/CompilationEnvironment.java index 3d450183..7b759e27 100644 --- a/src/main/java/de/dhbwstuttgart/environment/CompilationEnvironment.java +++ b/src/main/java/de/dhbwstuttgart/environment/CompilationEnvironment.java @@ -67,10 +67,10 @@ public class CompilationEnvironment { this.packageCrawler = new PackageCrawler(librarys); } - public JavaClassRegistry getRegistry(File forSourceFile) throws ClassNotFoundException, IOException { + public JavaClassRegistry getRegistry(File forSourceFile, ClassLoader classLoader) throws ClassNotFoundException, IOException { Map allNames; CompilationUnitContext tree = JavaTXParser.parse(forSourceFile); - allNames = GatherNames.getNames(tree, packageCrawler); + allNames = GatherNames.getNames(tree, packageCrawler, classLoader); return new JavaClassRegistry(allNames); } diff --git a/src/main/java/de/dhbwstuttgart/parser/SyntaxTreeGenerator/StatementGenerator.java b/src/main/java/de/dhbwstuttgart/parser/SyntaxTreeGenerator/StatementGenerator.java index 067430e2..9305310d 100644 --- a/src/main/java/de/dhbwstuttgart/parser/SyntaxTreeGenerator/StatementGenerator.java +++ b/src/main/java/de/dhbwstuttgart/parser/SyntaxTreeGenerator/StatementGenerator.java @@ -279,9 +279,21 @@ public class StatementGenerator { } - private Statement convert(Java8Parser.ClassInstanceCreationExpressionContext stmt) { - //TODO - throw new NotImplementedException(); + private Statement convert(Java8Parser.ClassInstanceCreationExpressionContext newExpression) { + Java8Parser.TypeArgumentsContext genericArgs = null; + if(newExpression.expressionName()!= null)throw new NotImplementedException(); + if(newExpression.typeArgumentsOrDiamond()!= null){ + if(newExpression.typeArgumentsOrDiamond().typeArguments()!=null){ + genericArgs = newExpression.typeArgumentsOrDiamond().typeArguments(); + } + } + if(newExpression.typeArguments()!= null)throw new NotImplementedException(); + + TerminalNode identifier = newExpression.Identifier(0); + RefType newClass = (RefType) TypeGenerator.convertTypeName(identifier.getText(),genericArgs,identifier.getSymbol(),reg,generics); + + ArgumentList args = convert(newExpression.argumentList()); + return new NewClass(newClass, args, newExpression.getStart()); } private Statement convert(Java8Parser.PreIncrementExpressionContext stmt) { diff --git a/src/main/java/de/dhbwstuttgart/parser/SyntaxTreeGenerator/SyntaxTreeGenerator.java b/src/main/java/de/dhbwstuttgart/parser/SyntaxTreeGenerator/SyntaxTreeGenerator.java index 140b3432..c374dd06 100644 --- a/src/main/java/de/dhbwstuttgart/parser/SyntaxTreeGenerator/SyntaxTreeGenerator.java +++ b/src/main/java/de/dhbwstuttgart/parser/SyntaxTreeGenerator/SyntaxTreeGenerator.java @@ -19,6 +19,7 @@ import de.dhbwstuttgart.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric; import de.dhbwstuttgart.syntaxtree.type.TypePlaceholder; import java.lang.reflect.Modifier; +import java.net.URL; import java.sql.Ref; import java.util.*; import java.util.stream.Collectors; @@ -74,10 +75,10 @@ public class SyntaxTreeGenerator{ return ret; } - public SourceFile convert(Java8Parser.CompilationUnitContext ctx, PackageCrawler packageCrawler) throws ClassNotFoundException{ + public SourceFile convert(Java8Parser.CompilationUnitContext ctx, PackageCrawler packageCrawler, ClassLoader classLoader) throws ClassNotFoundException{ if(ctx.packageDeclaration()!=null)this.pkgName = convert(ctx.packageDeclaration()); List classes = new ArrayList<>(); - Map imports = GatherNames.getImports(ctx, packageCrawler); + Map imports = GatherNames.getImports(ctx, packageCrawler, classLoader); this.imports = imports.keySet().stream().map(name -> reg.getName(name)).collect(Collectors.toSet()); for(Java8Parser.TypeDeclarationContext typeDecl : ctx.typeDeclaration()){ ClassOrInterface newClass; diff --git a/src/main/java/de/dhbwstuttgart/parser/scope/GatherNames.java b/src/main/java/de/dhbwstuttgart/parser/scope/GatherNames.java index 69481508..31c6d375 100644 --- a/src/main/java/de/dhbwstuttgart/parser/scope/GatherNames.java +++ b/src/main/java/de/dhbwstuttgart/parser/scope/GatherNames.java @@ -1,9 +1,8 @@ package de.dhbwstuttgart.parser.scope; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.*; import de.dhbwstuttgart.parser.antlr.Java8BaseListener; import de.dhbwstuttgart.syntaxtree.AbstractASTWalker; @@ -15,7 +14,7 @@ import de.dhbwstuttgart.parser.antlr.Java8Parser; public class GatherNames { - public static Map getNames(Java8Parser.CompilationUnitContext ctx, PackageCrawler packages) throws ClassNotFoundException{ + public static Map getNames(Java8Parser.CompilationUnitContext ctx, PackageCrawler packages, ClassLoader classLoader) throws ClassNotFoundException{ Map ret = new HashMap<>(); String pkgName = getPackageName(ctx); String nameString = ""; @@ -64,14 +63,13 @@ public class GatherNames { } } } - ret.putAll(getImports(ctx, packages)); + ret.putAll(getImports(ctx, packages, classLoader)); return ret; } - public static Map getImports(Java8Parser.CompilationUnitContext ctx, PackageCrawler packages) throws ClassNotFoundException { + public static Map getImports(Java8Parser.CompilationUnitContext ctx, PackageCrawler packages, ClassLoader classLoader) throws ClassNotFoundException { Map ret = new HashMap<>(); - ClassLoader classLoader = ClassLoader.getSystemClassLoader(); //ret.putAll(packages.getClassNames("java.lang")); for(Java8Parser.ImportDeclarationContext importDeclCtx : ctx.importDeclaration()){ if(importDeclCtx.singleTypeImportDeclaration() != null){ diff --git a/src/test/java/packages/ImportTest.java b/src/test/java/packages/ImportTest.java index a6fbc075..6487c9ab 100644 --- a/src/test/java/packages/ImportTest.java +++ b/src/test/java/packages/ImportTest.java @@ -1,5 +1,6 @@ package packages; +import com.google.common.collect.Lists; import de.dhbwstuttgart.core.JavaTXCompiler; import junit.framework.TestCase; import org.junit.Before; @@ -7,6 +8,7 @@ import org.junit.Test; import java.io.File; import java.io.IOException; +import java.net.URL; public class ImportTest extends TestCase { @@ -31,7 +33,9 @@ public class ImportTest extends TestCase { @Test public void testSetPackageNameInBytecodeAndOutputFolder() throws IOException, ClassNotFoundException { - JavaTXCompiler compiler = new JavaTXCompiler(new File(rootDirectory+"ImportTest.jav")); + JavaTXCompiler compiler = new JavaTXCompiler( + Lists.newArrayList(new File(rootDirectory+"ImportTest.jav")), + Lists.newArrayList(new URL("file://"+rootDirectory+"output/"))); compiler.typeInference(); File f = new File(rootDirectory + "output/de/test/ImportTest.class"); if(f.exists() && !f.isDirectory()) { diff --git a/vorgehen.md b/vorgehen.md index 834c49e7..b9af4d76 100644 --- a/vorgehen.md +++ b/vorgehen.md @@ -15,10 +15,13 @@ * Java kompiliert in den gleichen Ordner wie die source file * Java erhält eine liste von Source Files, die es kompilieren soll * anhand von deren Standort lassen sich relativ die Position von kompilierten Class-files bestimmen + * macht der javac Compiler allerdings nicht + * er nimmt sein Running Directory als classPath standardmäßig, falls keiner angegeben + * javac geht davon aus, dass CP richtig gesetzt wird, oder javac im Source-Root ausgeführt wird * -cp path or -classpath path Specifies where to find user class files, and (optionally) annotation processors and source files. This class path overrides the user class path in the CLASSPATH environment variable. If neither CLASSPATH, -cp nor -classpath is specified, then the - user class path is the current directory. See Setting the Class Path. + user class path is the current directory. See Setting the Class Path. * Compiler kontrolliert nicht, ob package im korrekten Ordner ist * auch keine Warnung @@ -46,8 +49,11 @@ * Für die Tests muss korrekter Classpath gesetzt werden ### Stand ### -TODO +TODO: +* es muss überall wo im Quellcode ClassLoader.getSystemClassLoader() oder ein andere Classloader verwendet wird, + * dieser ausgetauscht werden mit dem classLaoder, welcher bei der Instanzierung von JavaTXCompiler erstellt wird ## Class files mit packageNamen versehen * In die Class file muss noch der korrekte name geschrieben werden * kann möglicherweise ASM + * wurde bereits erledigt -> TODO: Testen From 1d16b9f2b95a8fcb439e2eea9825f11a520d2998 Mon Sep 17 00:00:00 2001 From: JanUlrich Date: Mon, 16 Dec 2019 00:55:04 +0100 Subject: [PATCH 07/11] Documentation --- vorgehen.md | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/vorgehen.md b/vorgehen.md index 834c49e7..c85f2767 100644 --- a/vorgehen.md +++ b/vorgehen.md @@ -41,13 +41,21 @@ ## Class files einlesen * Wenn Classpath übergeben * Suchen in Classpath + packageName + * Müsste eigentlich UTLClassLoader automatisch machen (also packageNamen anfügen) * Wenn nichts übergeben * dann currentDirectory + packageName * Für die Tests muss korrekter Classpath gesetzt werden ### Stand ### -TODO +* In der GatherNames Klasse muss ein URLClassloader angefügt werden + * siehe ImportTest +* Es muss ein Classpath Parameter an den Compiler angefügt werden + * Wird dieser nicht gesetzt, so wird nur im Root-Verzeichnis nach Klassen gesucht + * root = Input Jav-Files - deren Package Namen ## Class files mit packageNamen versehen * In die Class file muss noch der korrekte name geschrieben werden - * kann möglicherweise ASM + * Kann ASM mittesl `cw.visit("name/mit/slashe/Getrennt"..` +## Stand ## +* bereits implementiert + * TODO TESTEN From 0378c17e7d61de3bf7c836e1aab823ff60038d58 Mon Sep 17 00:00:00 2001 From: JanUlrich Date: Sun, 22 Dec 2019 14:27:54 +0100 Subject: [PATCH 08/11] ClassLoader austauschen gegen den Classloader, welcher in JavaCompilerCore erstellt wird --- .../de/dhbwstuttgart/bytecode/BytecodeGen.java | 4 ++-- .../bytecode/BytecodeGenMethod.java | 18 ++++++++++-------- .../de/dhbwstuttgart/core/JavaTXCompiler.java | 8 ++++---- .../environment/CompilationEnvironment.java | 1 - .../SyntaxTreeGenerator/FCGenerator.java | 18 +++++++++--------- .../sat/asp/writer/ASPFactory.java | 8 ++++---- .../sat/asp/writer/ASPGencayFactory.java | 8 ++++---- .../syntaxtree/factory/UnifyTypeFactory.java | 4 ++-- src/test/java/asp/ClingoTest.java | 2 +- src/test/java/asp/UnifyWithoutWildcards.java | 2 +- src/test/java/asp/gencay/GeneratorTest.java | 4 ++-- src/test/java/asp/typeinference/ASPTest.java | 2 +- .../finiteClosure/SuperInterfacesTest.java | 4 ++-- vorgehen.md | 2 ++ 14 files changed, 44 insertions(+), 41 deletions(-) diff --git a/src/main/java/de/dhbwstuttgart/bytecode/BytecodeGen.java b/src/main/java/de/dhbwstuttgart/bytecode/BytecodeGen.java index fff65180..b5ac3e0b 100644 --- a/src/main/java/de/dhbwstuttgart/bytecode/BytecodeGen.java +++ b/src/main/java/de/dhbwstuttgart/bytecode/BytecodeGen.java @@ -270,7 +270,7 @@ public class BytecodeGen implements ASTVisitor { constructorPos += 1; BytecodeGenMethod gen = new BytecodeGenMethod(className, superClass, resultSet, field, mv, paramsAndLocals, cw, - genericsAndBoundsMethod, genericsAndBounds, isInterface, classFiles, sf, path, block, constructorPos); + genericsAndBoundsMethod, genericsAndBounds, isInterface, classFiles, sf, path, block, constructorPos, ClassLoader.getSystemClassLoader()); if (!field.getParameterList().iterator().hasNext() && !(field.block.statements.get(field.block.statements.size() - 1) instanceof ReturnVoid)) { mv.visitInsn(Opcodes.RETURN); @@ -351,7 +351,7 @@ public class BytecodeGen implements ASTVisitor { mv.visitCode(); BytecodeGenMethod gen = new BytecodeGenMethod(className, superClass, resultSet, method, mv, paramsAndLocals, cw, - genericsAndBoundsMethod, genericsAndBounds, isInterface, classFiles, sf, path); + genericsAndBoundsMethod, genericsAndBounds, isInterface, classFiles, sf, path, ClassLoader.getSystemClassLoader()); mv.visitMaxs(0, 0); mv.visitEnd(); diff --git a/src/main/java/de/dhbwstuttgart/bytecode/BytecodeGenMethod.java b/src/main/java/de/dhbwstuttgart/bytecode/BytecodeGenMethod.java index 04f895fe..b0ada708 100644 --- a/src/main/java/de/dhbwstuttgart/bytecode/BytecodeGenMethod.java +++ b/src/main/java/de/dhbwstuttgart/bytecode/BytecodeGenMethod.java @@ -77,11 +77,13 @@ public class BytecodeGenMethod implements StatementVisitor { private int constructorPos = 0; private ArrayList varsFunInterface = new ArrayList<>();; + private final ClassLoader classLoader; + // generate bytecode for constructor public BytecodeGenMethod(JavaClassName className, String superClass, ResultSet resultSet, Method m, MethodVisitor mv, HashMap paramsAndLocals, ClassWriter cw, HashMap genericsAndBoundsMethod, HashMap genericsAndBounds, boolean isInterface, HashMap classFiles, - SourceFile sf, String path, Block block, int constructorPos) { + SourceFile sf, String path, Block block, int constructorPos, ClassLoader classLoader) { this.className = className; this.superClass = superClass; @@ -99,16 +101,15 @@ public class BytecodeGenMethod implements StatementVisitor { this.path = path; this.lamCounter = -1; this.constructorPos = constructorPos; + this.classLoader = classLoader; if(block != null) this.blockFieldInit = block; this.m.block.accept(this); - - } public BytecodeGenMethod(JavaClassName className, String superClass,ResultSet resultSet, Method m, MethodVisitor mv, HashMap paramsAndLocals, ClassWriter cw, HashMap genericsAndBoundsMethod, - HashMap genericsAndBounds, boolean isInterface, HashMap classFiles, SourceFile sf,String path) { + HashMap genericsAndBounds, boolean isInterface, HashMap classFiles, SourceFile sf,String path, ClassLoader classLoader) { this.className = className; this.superClass = superClass; @@ -125,14 +126,14 @@ public class BytecodeGenMethod implements StatementVisitor { this.sf = sf; this.path = path; this.lamCounter = -1; + this.classLoader = classLoader; if (!isInterface) this.m.block.accept(this); - } public BytecodeGenMethod(JavaClassName className, ClassWriter cw, LambdaExpression lambdaExpression, ArrayList usedVars, ResultSet resultSet, MethodVisitor mv, int indexOfFirstParamLam, boolean isInterface, HashMap classFiles, String path, int lamCounter, SourceFile sf,HashMap genericsAndBoundsMethod, - HashMap genericsAndBounds) { + HashMap genericsAndBounds, ClassLoader classLoader) { this.className = className; this.cw = cw; this.resultSet = resultSet; @@ -145,6 +146,7 @@ public class BytecodeGenMethod implements StatementVisitor { this.sf = sf; this.genericsAndBoundsMethod = genericsAndBoundsMethod; this.genericsAndBounds = genericsAndBounds; + this.classLoader = classLoader; Iterator itr = lambdaExpression.params.iterator(); int i = indexOfFirstParamLam; @@ -637,7 +639,7 @@ public class BytecodeGenMethod implements StatementVisitor { new BytecodeGenMethod(className, cw,lambdaExpression, usedVars,this.resultSet, mvLambdaBody, indexOfFirstParamLam, isInterface, classFiles,this.path, lamCounter, sf, genericsAndBoundsMethod, - genericsAndBounds); + genericsAndBounds, classLoader); mvLambdaBody.visitMaxs(0, 0); mvLambdaBody.visitEnd(); @@ -757,7 +759,7 @@ public class BytecodeGenMethod implements StatementVisitor { MethodCallHelper helper = new MethodCallHelper(methodCall, sf, resultSet, path); - ClassLoader cLoader = ClassLoader.getSystemClassLoader(); + ClassLoader cLoader = this.classLoader; // This will be used if the class is not standard class (not in API) ClassLoader cLoader2; diff --git a/src/main/java/de/dhbwstuttgart/core/JavaTXCompiler.java b/src/main/java/de/dhbwstuttgart/core/JavaTXCompiler.java index 61f90e42..f79a3a35 100644 --- a/src/main/java/de/dhbwstuttgart/core/JavaTXCompiler.java +++ b/src/main/java/de/dhbwstuttgart/core/JavaTXCompiler.java @@ -98,7 +98,7 @@ public class JavaTXCompiler { for (JavaClassName name : sourceFiles.get(forSourceFile).getImports()) { //TODO: Hier werden imports von eigenen (.jav) Klassen nicht beachtet ClassOrInterface importedClass = ASTFactory.createClass( - ClassLoader.getSystemClassLoader().loadClass(name.toString())); + classLoader.loadClass(name.toString())); importedClasses.add(importedClass); } allClasses.addAll(importedClasses); @@ -135,7 +135,7 @@ public class JavaTXCompiler { for (JavaClassName name : forSourceFile.getImports()) { // TODO: Hier werden imports von eigenen (.jav) Klassen nicht beachtet ClassOrInterface importedClass = ASTFactory - .createClass(ClassLoader.getSystemClassLoader().loadClass(name.toString())); + .createClass(classLoader.loadClass(name.toString())); importedClasses.add(importedClass); allClasses.addAll(importedClasses); } @@ -304,7 +304,7 @@ public class JavaTXCompiler { logFile = logFile == null ? new FileWriter(new File("log_" + sourceFiles.keySet().iterator().next().getName())) : logFile; - IFiniteClosure finiteClosure = UnifyTypeFactory.generateFC(allClasses, logFile); + IFiniteClosure finiteClosure = UnifyTypeFactory.generateFC(allClasses, logFile, classLoader); System.out.println(finiteClosure); urm = new UnifyResultModel(cons, finiteClosure); urm.addUnifyResultListener(resultListener); @@ -472,7 +472,7 @@ public class JavaTXCompiler { // File(System.getProperty("user.dir")+"/src/test/resources/logFiles/"+"log_"+sourceFiles.keySet().iterator().next().getName())); new FileWriter(new File(System.getProperty("user.dir") + "/logFiles/" + "log_" + sourceFiles.keySet().iterator().next().getName())); - IFiniteClosure finiteClosure = UnifyTypeFactory.generateFC(allClasses, logFile); + IFiniteClosure finiteClosure = UnifyTypeFactory.generateFC(allClasses, logFile, classLoader); System.out.println(finiteClosure); ConstraintSet unifyCons = UnifyTypeFactory.convert(cons); diff --git a/src/main/java/de/dhbwstuttgart/environment/CompilationEnvironment.java b/src/main/java/de/dhbwstuttgart/environment/CompilationEnvironment.java index 7b759e27..43196b6f 100644 --- a/src/main/java/de/dhbwstuttgart/environment/CompilationEnvironment.java +++ b/src/main/java/de/dhbwstuttgart/environment/CompilationEnvironment.java @@ -50,7 +50,6 @@ public class CompilationEnvironment { */ //String bootClassPath = System.getProperty("sun.boot.class.path"); // ClassLoader cl = ClassLoader.getPlatformClassLoader(); - ClassLoader cl = ClassLoader.getSystemClassLoader(); String bootClassPath = System.getProperty("java.class.path"); librarys = new ArrayList<>(); for(String path : bootClassPath.split(File.pathSeparator)) { diff --git a/src/main/java/de/dhbwstuttgart/parser/SyntaxTreeGenerator/FCGenerator.java b/src/main/java/de/dhbwstuttgart/parser/SyntaxTreeGenerator/FCGenerator.java index 29c53981..71dcef52 100644 --- a/src/main/java/de/dhbwstuttgart/parser/SyntaxTreeGenerator/FCGenerator.java +++ b/src/main/java/de/dhbwstuttgart/parser/SyntaxTreeGenerator/FCGenerator.java @@ -22,16 +22,16 @@ public class FCGenerator { * * @param availableClasses - Alle geparsten Klassen */ - public static Set toUnifyFC(Collection availableClasses) throws ClassNotFoundException { - return toFC(availableClasses).stream().map(t -> UnifyTypeFactory.convert(t)).collect(Collectors.toSet()); + public static Set toUnifyFC(Collection availableClasses, ClassLoader classLoader) throws ClassNotFoundException { + return toFC(availableClasses, classLoader).stream().map(t -> UnifyTypeFactory.convert(t)).collect(Collectors.toSet()); } - public static Set toFC(Collection availableClasses) throws ClassNotFoundException { + public static Set toFC(Collection availableClasses, ClassLoader classLoader) throws ClassNotFoundException { HashSet pairs = new HashSet<>(); //PL 2018-09-18: gtvs vor die for-Schleife gezogen, damit immer die gleichen Typeplaceholder eingesetzt werden. HashMap gtvs = new HashMap<>(); for(ClassOrInterface cly : availableClasses){ - pairs.addAll(getSuperTypes(cly, availableClasses, gtvs)); + pairs.addAll(getSuperTypes(cly, availableClasses, gtvs, classLoader)); } return pairs; } @@ -48,8 +48,8 @@ public class FCGenerator { * @param forType * @return */ - private static List getSuperTypes(ClassOrInterface forType, Collection availableClasses) throws ClassNotFoundException { - return getSuperTypes(forType, availableClasses, new HashMap<>()); + private static List getSuperTypes(ClassOrInterface forType, Collection availableClasses, ClassLoader classLoader) throws ClassNotFoundException { + return getSuperTypes(forType, availableClasses, new HashMap<>(), classLoader); } /** @@ -61,7 +61,7 @@ public class FCGenerator { * @throws ClassNotFoundException */ private static List getSuperTypes(ClassOrInterface forType, Collection availableClasses, - HashMap gtvs) throws ClassNotFoundException { + HashMap gtvs, ClassLoader classLoader) throws ClassNotFoundException { List params = new ArrayList<>(); //Die GTVs, die in forType hinzukommen: HashMap newGTVs = new HashMap<>(); @@ -86,7 +86,7 @@ public class FCGenerator { ClassOrInterface superClass; if(!hasSuperclass.isPresent()) //Wenn es die Klasse in den available Klasses nicht gibt wird sie im Classpath gesucht. Ansonsten Exception { - superClass = ASTFactory.createClass(ClassLoader.getSystemClassLoader().loadClass(superType.getName().toString())); + superClass = ASTFactory.createClass(classLoader.loadClass(superType.getName().toString())); }else{ superClass = hasSuperclass.get(); } @@ -120,7 +120,7 @@ public class FCGenerator { if(superClass.getClassName().equals(ASTFactory.createObjectClass().getClassName())){ superTypes = Arrays.asList(new Pair(ASTFactory.createObjectType(), ASTFactory.createObjectType(), PairOperator.SMALLER)); }else{ - superTypes = getSuperTypes(superClass, availableClasses, newGTVs); + superTypes = getSuperTypes(superClass, availableClasses, newGTVs, classLoader); } retList.add(ret); diff --git a/src/main/java/de/dhbwstuttgart/sat/asp/writer/ASPFactory.java b/src/main/java/de/dhbwstuttgart/sat/asp/writer/ASPFactory.java index 1777eabd..8cb61fee 100644 --- a/src/main/java/de/dhbwstuttgart/sat/asp/writer/ASPFactory.java +++ b/src/main/java/de/dhbwstuttgart/sat/asp/writer/ASPFactory.java @@ -16,9 +16,9 @@ import java.util.*; public class ASPFactory implements TypeVisitor{ - public static String generateASP(ConstraintSet constraints, Collection fcClasses) throws ClassNotFoundException{ + public static String generateASP(ConstraintSet constraints, Collection fcClasses, ClassLoader classLoader) throws ClassNotFoundException{ ASPFactory factory = new ASPFactory(); - factory.convertFC(fcClasses); + factory.convertFC(fcClasses, classLoader); List> constraints1 = constraints.cartesianProduct().iterator().next(); for(Constraint constraint : constraints1){ for(Pair p : constraint){ @@ -32,8 +32,8 @@ public class ASPFactory implements TypeVisitor{ ASPWriter writer = new ASPWriter(); boolean isFCType = false; - private void convertFC(Collection classes) throws ClassNotFoundException { - Set fc = FCGenerator.toFC(classes); + private void convertFC(Collection classes, ClassLoader classLoader) throws ClassNotFoundException { + Set fc = FCGenerator.toFC(classes, classLoader); isFCType = true; for(Pair fcp : fc){ convertPair(fcp); diff --git a/src/main/java/de/dhbwstuttgart/sat/asp/writer/ASPGencayFactory.java b/src/main/java/de/dhbwstuttgart/sat/asp/writer/ASPGencayFactory.java index 11408c25..242c63e6 100644 --- a/src/main/java/de/dhbwstuttgart/sat/asp/writer/ASPGencayFactory.java +++ b/src/main/java/de/dhbwstuttgart/sat/asp/writer/ASPGencayFactory.java @@ -55,9 +55,9 @@ public class ASPGencayFactory implements TypeVisitor { return ret; } - public static String generateASP(ConstraintSet constraints, Collection fcClasses) throws ClassNotFoundException{ + public static String generateASP(ConstraintSet constraints, Collection fcClasses, ClassLoader classLoader) throws ClassNotFoundException{ ASPGencayFactory factory = new ASPGencayFactory(); - factory.convertFC(fcClasses); + factory.convertFC(fcClasses, classLoader); List> constraints1 = constraints.cartesianProduct().iterator().next(); for(Constraint constraint : constraints1){ for(Pair p : constraint){ @@ -69,8 +69,8 @@ public class ASPGencayFactory implements TypeVisitor { return factory.writer.getASPFile(); } - private void convertFC(Collection classes) throws ClassNotFoundException { - Set fc = FCGenerator.toFC(classes); + private void convertFC(Collection classes, ClassLoader classLoader) throws ClassNotFoundException { + Set fc = FCGenerator.toFC(classes, classLoader); isFCType = true; for(Pair fcp : fc){ generateTheta((RefType) fcp.TA1); diff --git a/src/main/java/de/dhbwstuttgart/syntaxtree/factory/UnifyTypeFactory.java b/src/main/java/de/dhbwstuttgart/syntaxtree/factory/UnifyTypeFactory.java index 4241af34..33d137eb 100644 --- a/src/main/java/de/dhbwstuttgart/syntaxtree/factory/UnifyTypeFactory.java +++ b/src/main/java/de/dhbwstuttgart/syntaxtree/factory/UnifyTypeFactory.java @@ -31,7 +31,7 @@ public class UnifyTypeFactory { private static ArrayList PLACEHOLDERS = new ArrayList<>(); - public static FiniteClosure generateFC(List fromClasses, Writer logFile) throws ClassNotFoundException { + public static FiniteClosure generateFC(List fromClasses, Writer logFile, ClassLoader classLoader) throws ClassNotFoundException { /* Die transitive Hülle muss funktionieren. Man darf schreiben List extends AL @@ -42,7 +42,7 @@ public class UnifyTypeFactory { Generell dürfen sie immer die gleichen Namen haben. TODO: die transitive Hülle bilden */ - return new FiniteClosure(FCGenerator.toUnifyFC(fromClasses), logFile); + return new FiniteClosure(FCGenerator.toUnifyFC(fromClasses, classLoader), logFile); } public static UnifyPair generateSmallerPair(UnifyType tl, UnifyType tr){ diff --git a/src/test/java/asp/ClingoTest.java b/src/test/java/asp/ClingoTest.java index 90635bde..ea09add3 100644 --- a/src/test/java/asp/ClingoTest.java +++ b/src/test/java/asp/ClingoTest.java @@ -25,7 +25,7 @@ public class ClingoTest { @Test public void test() throws IOException, InterruptedException, ClassNotFoundException { String content = ""; - content = ASPFactory.generateASP(this.getPairs(), this.getFC()); + content = ASPFactory.generateASP(this.getPairs(), this.getFC(), ClassLoader.getSystemClassLoader()); PrintWriter writer = new PrintWriter(tempDirectory + "test.lp", "UTF-8"); writer.println(content); diff --git a/src/test/java/asp/UnifyWithoutWildcards.java b/src/test/java/asp/UnifyWithoutWildcards.java index 6f69d639..c1a84702 100644 --- a/src/test/java/asp/UnifyWithoutWildcards.java +++ b/src/test/java/asp/UnifyWithoutWildcards.java @@ -40,7 +40,7 @@ public class UnifyWithoutWildcards { public ResultSet run(ConstraintSet toTest) throws IOException, InterruptedException, ClassNotFoundException { String content = ""; - content = ASPFactory.generateASP(toTest, this.getFC()); + content = ASPFactory.generateASP(toTest, this.getFC(), ClassLoader.getSystemClassLoader()); PrintWriter writer = new PrintWriter(tempDirectory + "test.lp", "UTF-8"); writer.println(content); diff --git a/src/test/java/asp/gencay/GeneratorTest.java b/src/test/java/asp/gencay/GeneratorTest.java index 2c9fc46f..36a74bde 100644 --- a/src/test/java/asp/gencay/GeneratorTest.java +++ b/src/test/java/asp/gencay/GeneratorTest.java @@ -35,7 +35,7 @@ public class GeneratorTest extends UnifyWithoutWildcards{ RefType t2 = new RefType(new JavaClassName("java.util.List"), list2, new NullToken()); testSet.addUndConstraint(new Pair(t1, t2, PairOperator.SMALLERDOT)); String resultSet = ASPGencayFactory.generateASP(testSet, - new HashSet<>(Arrays.asList(ASTFactory.createClass(List.class)))); + new HashSet<>(Arrays.asList(ASTFactory.createClass(List.class))), ClassLoader.getSystemClassLoader()); System.out.println(resultSet); } @@ -47,7 +47,7 @@ public class GeneratorTest extends UnifyWithoutWildcards{ RefType t1 = new RefType(new JavaClassName("asp.UnifyWithoutWildcards$Matrix"), list1, new NullToken()); RefType t2 = new RefType(new JavaClassName("java.util.HashMap"), list2, new NullToken()); testSet.addUndConstraint(new Pair(t1, t2, PairOperator.SMALLERDOT)); - String resultSet = ASPGencayFactory.generateASP(testSet, this.getFC()); + String resultSet = ASPGencayFactory.generateASP(testSet, this.getFC(), ClassLoader.getSystemClassLoader()); System.out.println(resultSet); } diff --git a/src/test/java/asp/typeinference/ASPTest.java b/src/test/java/asp/typeinference/ASPTest.java index 5a43b6a9..989e1233 100644 --- a/src/test/java/asp/typeinference/ASPTest.java +++ b/src/test/java/asp/typeinference/ASPTest.java @@ -55,7 +55,7 @@ public class ASPTest { } final ConstraintSet cons = compiler.getConstraints(); - String asp = ASPFactory.generateASP(cons, allClasses); + String asp = ASPFactory.generateASP(cons, allClasses, ClassLoader.getSystemClassLoader()); System.out.println(asp); } diff --git a/src/test/java/finiteClosure/SuperInterfacesTest.java b/src/test/java/finiteClosure/SuperInterfacesTest.java index 0e1368c3..d74215b7 100644 --- a/src/test/java/finiteClosure/SuperInterfacesTest.java +++ b/src/test/java/finiteClosure/SuperInterfacesTest.java @@ -14,14 +14,14 @@ public class SuperInterfacesTest { public void test() throws ClassNotFoundException { Collection classes = new ArrayList<>(); classes.add(ASTFactory.createClass(TestClass.class)); - System.out.println(FCGenerator.toFC(classes)); + System.out.println(FCGenerator.toFC(classes, ClassLoader.getSystemClassLoader())); } @Test public void testGeneric() throws ClassNotFoundException { Collection classes = new ArrayList<>(); classes.add(ASTFactory.createClass(TestClassGeneric.class)); - System.out.println(FCGenerator.toFC(classes)); + System.out.println(FCGenerator.toFC(classes, ClassLoader.getSystemClassLoader())); } } diff --git a/vorgehen.md b/vorgehen.md index 7ee69df2..0854c152 100644 --- a/vorgehen.md +++ b/vorgehen.md @@ -59,3 +59,5 @@ TODO: * kann möglicherweise ASM * Kann ASM mittesl `cw.visit("name/mit/slashe/Getrennt"..` * wurde bereits erledigt -> TODO: Testen + +## Console Interface um Parameter -classpath und -output directory erweitern From 75eaee6644f35ce7151a229ca3c3b897214713bb Mon Sep 17 00:00:00 2001 From: JanUlrich Date: Sun, 22 Dec 2019 17:59:40 +0100 Subject: [PATCH 09/11] Abgabeprotokoll --- abgabeprotokoll.md | 15 +++++++++++++++ src/test/java/packages/ImportTest.java | 20 +++++++++++++++----- 2 files changed, 30 insertions(+), 5 deletions(-) create mode 100644 abgabeprotokoll.md diff --git a/abgabeprotokoll.md b/abgabeprotokoll.md new file mode 100644 index 00000000..6ec54961 --- /dev/null +++ b/abgabeprotokoll.md @@ -0,0 +1,15 @@ +# JavaTXCompiler Klasse +* Konstruktor hat einen weiteren Parameter +* contextPath + * Arrays aus URLs (file-urls) +* Parameter ist Optional +* wird er gesetzt, so werden Classfiles aus den übergebenen Pfaden geladen + * die übergebenen Pfade müssen dabei die Source-Roots sein + * Beispiel: + `import de.test.Klasse;` + * `Klasse.class` liegt in `output/de/test/Klasse.class` + * dann muss contextpath auf `output` gesetzt werden +* wird der Parameter nicht übergeben, so wird der Sourceroot auf das Verzeichnis gesetzt, in dem der Compiler ausgeführt wird +* dies ist das Verhalten vom javac Compiler + + diff --git a/src/test/java/packages/ImportTest.java b/src/test/java/packages/ImportTest.java index 6487c9ab..575da032 100644 --- a/src/test/java/packages/ImportTest.java +++ b/src/test/java/packages/ImportTest.java @@ -24,11 +24,6 @@ public class ImportTest extends TestCase { compiler.generateBytecode(rootDirectory + "output/"); File f = new File(rootDirectory + "output/de/test/ToImport.class"); assertTrue(f.exists()); - compiler = new JavaTXCompiler(new File(rootDirectory+"ToImport.jav")); - compiler.typeInference(); - compiler.generateBytecode(null); - f = new File(rootDirectory + "output/de/test/ToImport.class"); - assertTrue(f.exists()); } @Test @@ -45,4 +40,19 @@ public class ImportTest extends TestCase { f = new File(rootDirectory + "output/de/test/ImportTest.class"); assertTrue(f.exists()); } + + @Test + public void testSetPackageNameInBytecodeAndStandardOutputFolder() throws IOException, ClassNotFoundException { + JavaTXCompiler compiler = new JavaTXCompiler( + Lists.newArrayList(new File(rootDirectory+"ImportTest.jav")), + Lists.newArrayList(new URL("file://"+rootDirectory+"output/"))); + compiler.typeInference(); + File f = new File(rootDirectory + "ImportTest.class"); + if(f.exists() && !f.isDirectory()) { + f.delete(); + } + compiler.generateBytecode(null); + f = new File(rootDirectory + "ImportTest.class"); + assertTrue(f.exists()); + } } From 306af907c552c0c51d3dde43133983a1419e77c4 Mon Sep 17 00:00:00 2001 From: JanUlrich Date: Sun, 22 Dec 2019 22:32:40 +0100 Subject: [PATCH 10/11] Nicht mit mehreren Eingabedateien testen --- abgabeprotokoll.md | 4 +++ .../de/dhbwstuttgart/core/JavaTXCompiler.java | 4 +++ .../java/packages/CheckPackageFolder.java | 35 ++++++++++++++++++- .../packageTest/de/test/subpackage1/Test1.jav | 4 +++ .../packageTest/de/test/subpackage2/Test2.jav | 4 +++ 5 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 src/test/resources/javFiles/packageTest/de/test/subpackage1/Test1.jav create mode 100644 src/test/resources/javFiles/packageTest/de/test/subpackage2/Test2.jav diff --git a/abgabeprotokoll.md b/abgabeprotokoll.md index 6ec54961..db079dab 100644 --- a/abgabeprotokoll.md +++ b/abgabeprotokoll.md @@ -12,4 +12,8 @@ * wird der Parameter nicht übergeben, so wird der Sourceroot auf das Verzeichnis gesetzt, in dem der Compiler ausgeführt wird * dies ist das Verhalten vom javac Compiler +* generateBytecode - Methode hat neuen Parameter: path +* wird hier null übergeben, so wird die class-File in den gleichen Ordner wie die übergebene .jav File geschrieben +* wird hier ein Pfad übergeben, so gilt dieser als output root. + * Klassen werden in outputRoot/package/name/KlassenName.class geschrieben diff --git a/src/main/java/de/dhbwstuttgart/core/JavaTXCompiler.java b/src/main/java/de/dhbwstuttgart/core/JavaTXCompiler.java index f79a3a35..ee81d60d 100644 --- a/src/main/java/de/dhbwstuttgart/core/JavaTXCompiler.java +++ b/src/main/java/de/dhbwstuttgart/core/JavaTXCompiler.java @@ -766,6 +766,10 @@ public class JavaTXCompiler { return result; } + public void generateBytecode() throws ClassNotFoundException, IOException, BytecodeGeneratorError { + generateBytecode(null); + } + /** * @param path - can be null, then class file output is in the same directory as the parsed source files */ diff --git a/src/test/java/packages/CheckPackageFolder.java b/src/test/java/packages/CheckPackageFolder.java index 9644d5da..50b2773b 100644 --- a/src/test/java/packages/CheckPackageFolder.java +++ b/src/test/java/packages/CheckPackageFolder.java @@ -7,6 +7,7 @@ import org.junit.Test; import java.io.File; import java.io.IOException; +import java.util.Arrays; public class CheckPackageFolder extends TestCase { @@ -15,6 +16,38 @@ public class CheckPackageFolder extends TestCase { @Test public void testCorrectFolder1File() throws IOException, ClassNotFoundException { JavaTXCompiler compiler = new JavaTXCompiler(new File(rootDirectory+"packageNameTestWrongPackage.jav")); - assertTrue(true); //Es ist erlaubt falsche package Namen zu verwenden. Warnung wäre optional + compiler.typeInference(); + File f = new File(rootDirectory + "TestClass.class"); + if(f.exists() && !f.isDirectory()) { + f.delete(); + } + compiler.generateBytecode(); + f = new File(rootDirectory + "TestClass.class"); + assertTrue(f.exists()); //Es ist erlaubt falsche package Namen zu verwenden. Warnung wäre optional } + + /* + * Dieser Test wird übersprungen, da der Bytecode-Generator nicht mit zwei Eingabedateien gleichzeitig umgehen kann + @Test + public void testCorrectFolder2Files() throws IOException, ClassNotFoundException { + JavaTXCompiler compiler = new JavaTXCompiler(Arrays.asList( + new File(rootDirectory+"subpackage1/Test1.jav"), + new File(rootDirectory+"subpackage2/Test2.jav") + )); + compiler.typeInference(); + File f = new File(rootDirectory + "subpackage1/Test1.class"); + if(f.exists() && !f.isDirectory()) { + f.delete(); + } + File f2 = new File(rootDirectory + "subpackage2/Test2.class"); + if(f.exists() && !f.isDirectory()) { + f.delete(); + } + compiler.generateBytecode(); + f = new File(rootDirectory + "subpackage1/Test1.class"); + f2 = new File(rootDirectory + "subpackage2/Test2.class"); + assertTrue(f.exists()); + assertTrue(f2.exists()); + } + */ } diff --git a/src/test/resources/javFiles/packageTest/de/test/subpackage1/Test1.jav b/src/test/resources/javFiles/packageTest/de/test/subpackage1/Test1.jav new file mode 100644 index 00000000..a7011169 --- /dev/null +++ b/src/test/resources/javFiles/packageTest/de/test/subpackage1/Test1.jav @@ -0,0 +1,4 @@ +package de.test.subpackage1; + +class Test1{ +} \ No newline at end of file diff --git a/src/test/resources/javFiles/packageTest/de/test/subpackage2/Test2.jav b/src/test/resources/javFiles/packageTest/de/test/subpackage2/Test2.jav new file mode 100644 index 00000000..750f7612 --- /dev/null +++ b/src/test/resources/javFiles/packageTest/de/test/subpackage2/Test2.jav @@ -0,0 +1,4 @@ +package de.test.subpackage2; + +class Test2{ +} \ No newline at end of file From d0b6dbcd3082d5f582e9f58f939bb8f84934a74c Mon Sep 17 00:00:00 2001 From: JanUlrich Date: Sun, 22 Dec 2019 22:52:55 +0100 Subject: [PATCH 11/11] =?UTF-8?q?Tests=20anf=C3=BCgen=20und=20Bugs=20fixen?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dhbwstuttgart/bytecode/BytecodeGen.java | 10 ++++--- .../bytecode/BytecodeGenMethod.java | 2 +- .../de/dhbwstuttgart/core/JavaTXCompiler.java | 4 +-- src/test/java/packages/Bytecode.java | 2 ++ .../java/packages/CheckPackageFolder.java | 28 ++++++++++++++++++- src/test/java/packages/ImportTest.java | 28 +++++++++++++++++++ .../packageTest/de/test/ImportTest2.jav | 11 ++++++++ .../de/test/subpackage1/ToImport2.jav | 5 ++++ .../de/test/subpackage2/ToImport3.jav | 5 ++++ 9 files changed, 87 insertions(+), 8 deletions(-) create mode 100644 src/test/resources/javFiles/packageTest/de/test/ImportTest2.jav create mode 100644 src/test/resources/javFiles/packageTest/de/test/subpackage1/ToImport2.jav create mode 100644 src/test/resources/javFiles/packageTest/de/test/subpackage2/ToImport3.jav diff --git a/src/main/java/de/dhbwstuttgart/bytecode/BytecodeGen.java b/src/main/java/de/dhbwstuttgart/bytecode/BytecodeGen.java index b5ac3e0b..5091af5e 100644 --- a/src/main/java/de/dhbwstuttgart/bytecode/BytecodeGen.java +++ b/src/main/java/de/dhbwstuttgart/bytecode/BytecodeGen.java @@ -119,22 +119,24 @@ public class BytecodeGen implements ASTVisitor { private GenericsGeneratorResultForClass generatedGenerics; private Resolver resolver; + private final ClassLoader classLoader; public BytecodeGen(HashMap classFiles, Collection listOfResultSets, List simplifyResultsForAllSourceFiles, SourceFile sf, - String path) { + String path, ClassLoader classLoader) { this.classFiles = classFiles; this.listOfResultSets = listOfResultSets; this.simplifyResultsForAllSourceFiles = simplifyResultsForAllSourceFiles; this.sf = sf; this.path = path; this.pkgName = sf.getPkgName(); + this.classLoader = classLoader; } @Override public void visit(SourceFile sourceFile) { for (ClassOrInterface cl : sourceFile.getClasses()) { System.out.println("in Class: " + cl.getClassName().toString()); - BytecodeGen classGen = new BytecodeGen(classFiles, listOfResultSets, simplifyResultsForAllSourceFiles, sf, path); + BytecodeGen classGen = new BytecodeGen(classFiles, listOfResultSets, simplifyResultsForAllSourceFiles, sf, path, classLoader); cl.accept(classGen); classGen.writeClass(cl.getClassName()); } @@ -270,7 +272,7 @@ public class BytecodeGen implements ASTVisitor { constructorPos += 1; BytecodeGenMethod gen = new BytecodeGenMethod(className, superClass, resultSet, field, mv, paramsAndLocals, cw, - genericsAndBoundsMethod, genericsAndBounds, isInterface, classFiles, sf, path, block, constructorPos, ClassLoader.getSystemClassLoader()); + genericsAndBoundsMethod, genericsAndBounds, isInterface, classFiles, sf, path, block, constructorPos, classLoader); if (!field.getParameterList().iterator().hasNext() && !(field.block.statements.get(field.block.statements.size() - 1) instanceof ReturnVoid)) { mv.visitInsn(Opcodes.RETURN); @@ -351,7 +353,7 @@ public class BytecodeGen implements ASTVisitor { mv.visitCode(); BytecodeGenMethod gen = new BytecodeGenMethod(className, superClass, resultSet, method, mv, paramsAndLocals, cw, - genericsAndBoundsMethod, genericsAndBounds, isInterface, classFiles, sf, path, ClassLoader.getSystemClassLoader()); + genericsAndBoundsMethod, genericsAndBounds, isInterface, classFiles, sf, path, classLoader); mv.visitMaxs(0, 0); mv.visitEnd(); diff --git a/src/main/java/de/dhbwstuttgart/bytecode/BytecodeGenMethod.java b/src/main/java/de/dhbwstuttgart/bytecode/BytecodeGenMethod.java index b0ada708..136dec53 100644 --- a/src/main/java/de/dhbwstuttgart/bytecode/BytecodeGenMethod.java +++ b/src/main/java/de/dhbwstuttgart/bytecode/BytecodeGenMethod.java @@ -814,7 +814,7 @@ public class BytecodeGenMethod implements StatementVisitor { // mDesc = helper.generateBCForFunN(methCallType,typesOfParams); }else { try { - cLoader2 = new URLClassLoader(new URL[] {new URL("file://"+path)}); + cLoader2 = new URLClassLoader(new URL[] {new URL("file://"+path)}, classLoader); java.lang.reflect.Method[] methods = cLoader2.loadClass(clazz).getMethods(); System.out.println("Methods of " + receiverName + " "); for(int i = 0; i typeinferenceResult) throws IOException { try { List genericResults = getGeneratedGenericResultsForAllSourceFiles(typeinferenceResult); - BytecodeGen bytecodeGen = new BytecodeGen(classFiles,typeinferenceResult, genericResults, sf,path); + BytecodeGen bytecodeGen = new BytecodeGen(classFiles,typeinferenceResult, genericResults, sf,path, classLoader); bytecodeGen.visit(sf); this.writeClassFile(bytecodeGen.getClassFiles(), path); } catch (ClassNotFoundException e) { @@ -792,7 +792,7 @@ public class JavaTXCompiler { HashMap classFiles = new HashMap<>(); SourceFile sf = sourceFiles.get(f); BytecodeGen bytecodeGen = new BytecodeGen(classFiles, typeinferenceResult, simplifyResultsForAllSourceFiles, - sf, path); + sf, path, classLoader); bytecodeGen.visit(sf); if(path == null){ path = f.getParent(); //Set path to path of the parsed .jav file diff --git a/src/test/java/packages/Bytecode.java b/src/test/java/packages/Bytecode.java index 7a5c4c25..3fabed05 100644 --- a/src/test/java/packages/Bytecode.java +++ b/src/test/java/packages/Bytecode.java @@ -47,4 +47,6 @@ public class Bytecode extends TestCase { Class classToTest = loader.loadClass("de.test.TestClass"); Object instanceOfClass = classToTest.getDeclaredConstructor().newInstance(); } + + } diff --git a/src/test/java/packages/CheckPackageFolder.java b/src/test/java/packages/CheckPackageFolder.java index 50b2773b..b0cfbb8e 100644 --- a/src/test/java/packages/CheckPackageFolder.java +++ b/src/test/java/packages/CheckPackageFolder.java @@ -14,7 +14,7 @@ public class CheckPackageFolder extends TestCase { public static final String rootDirectory = System.getProperty("user.dir")+"/src/test/resources/javFiles/packageTest/de/test/"; @Test - public void testCorrectFolder1File() throws IOException, ClassNotFoundException { + public void testCorrectFolder1FileWithWrongPackageName() throws IOException, ClassNotFoundException { JavaTXCompiler compiler = new JavaTXCompiler(new File(rootDirectory+"packageNameTestWrongPackage.jav")); compiler.typeInference(); File f = new File(rootDirectory + "TestClass.class"); @@ -26,6 +26,32 @@ public class CheckPackageFolder extends TestCase { assertTrue(f.exists()); //Es ist erlaubt falsche package Namen zu verwenden. Warnung wäre optional } + @Test + public void testCorrectFolder1File() throws IOException, ClassNotFoundException { + JavaTXCompiler compiler = new JavaTXCompiler(new File(rootDirectory+"TestClass.jav")); + compiler.typeInference(); + File f = new File(rootDirectory + "TestClass.class"); + if(f.exists() && !f.isDirectory()) { + f.delete(); + } + compiler.generateBytecode(); + f = new File(rootDirectory + "TestClass.class"); + assertTrue(f.exists()); //Es ist erlaubt falsche package Namen zu verwenden. Warnung wäre optional + } + + @Test + public void testCorrectFolder1FileAndOutputDirectory() throws IOException, ClassNotFoundException { + JavaTXCompiler compiler = new JavaTXCompiler(new File(rootDirectory+"TestClass.jav")); + compiler.typeInference(); + File f = new File(rootDirectory + "output/de/test/TestClass.class"); + if(f.exists() && !f.isDirectory()) { + f.delete(); + } + compiler.generateBytecode(rootDirectory+"output/"); + f = new File(rootDirectory + "output/de/test/TestClass.class"); + assertTrue(f.exists()); //Es ist erlaubt falsche package Namen zu verwenden. Warnung wäre optional + } + /* * Dieser Test wird übersprungen, da der Bytecode-Generator nicht mit zwei Eingabedateien gleichzeitig umgehen kann @Test diff --git a/src/test/java/packages/ImportTest.java b/src/test/java/packages/ImportTest.java index 575da032..b13918c6 100644 --- a/src/test/java/packages/ImportTest.java +++ b/src/test/java/packages/ImportTest.java @@ -24,6 +24,18 @@ public class ImportTest extends TestCase { compiler.generateBytecode(rootDirectory + "output/"); File f = new File(rootDirectory + "output/de/test/ToImport.class"); assertTrue(f.exists()); + + compiler = new JavaTXCompiler(new File(rootDirectory+"subpackage1/ToImport2.jav")); + compiler.typeInference(); + compiler.generateBytecode(rootDirectory + "output/"); + f = new File(rootDirectory + "output/de/test/subpackage1/ToImport2.class"); + assertTrue(f.exists()); + + compiler = new JavaTXCompiler(new File(rootDirectory+"subpackage2/ToImport3.jav")); + compiler.typeInference(); + compiler.generateBytecode(rootDirectory + "output/"); + f = new File(rootDirectory + "output/de/test/subpackage2/ToImport3.class"); + assertTrue(f.exists()); } @Test @@ -55,4 +67,20 @@ public class ImportTest extends TestCase { f = new File(rootDirectory + "ImportTest.class"); assertTrue(f.exists()); } + + + @Test + public void testImportTwoClasses() throws IOException, ClassNotFoundException { + JavaTXCompiler compiler = new JavaTXCompiler( + Lists.newArrayList(new File(rootDirectory+"ImportTest2.jav")), + Lists.newArrayList(new URL("file://"+rootDirectory+"output/"))); + compiler.typeInference(); + File f = new File(rootDirectory + "ImportTest2.class"); + if(f.exists() && !f.isDirectory()) { + f.delete(); + } + compiler.generateBytecode(null); + f = new File(rootDirectory + "ImportTest2.class"); + assertTrue(f.exists()); + } } diff --git a/src/test/resources/javFiles/packageTest/de/test/ImportTest2.jav b/src/test/resources/javFiles/packageTest/de/test/ImportTest2.jav new file mode 100644 index 00000000..3526abc8 --- /dev/null +++ b/src/test/resources/javFiles/packageTest/de/test/ImportTest2.jav @@ -0,0 +1,11 @@ +package de.test; + +import de.test.subpackage1.ToImport2; +import de.test.subpackage2.ToImport3; + +class ImportTest2{ + void methode(){ + new ToImport2().m1(); + new ToImport3().m2(); + } +} \ No newline at end of file diff --git a/src/test/resources/javFiles/packageTest/de/test/subpackage1/ToImport2.jav b/src/test/resources/javFiles/packageTest/de/test/subpackage1/ToImport2.jav new file mode 100644 index 00000000..bcc67b95 --- /dev/null +++ b/src/test/resources/javFiles/packageTest/de/test/subpackage1/ToImport2.jav @@ -0,0 +1,5 @@ +package de.test.subpackage1; + +class ToImport2{ +void m1(){} +} \ No newline at end of file diff --git a/src/test/resources/javFiles/packageTest/de/test/subpackage2/ToImport3.jav b/src/test/resources/javFiles/packageTest/de/test/subpackage2/ToImport3.jav new file mode 100644 index 00000000..3efd8fff --- /dev/null +++ b/src/test/resources/javFiles/packageTest/de/test/subpackage2/ToImport3.jav @@ -0,0 +1,5 @@ +package de.test.subpackage2; + +class ToImport3{ +void m2(){} +} \ No newline at end of file