diff --git a/.gitignore b/.gitignore index c134c76..8c5079b 100644 --- a/.gitignore +++ b/.gitignore @@ -76,4 +76,10 @@ fabric.properties # Android studio 3.1+ serialized cache file .idea/caches/build_file_checksums.ser -/target \ No newline at end of file +/target +src/main/resources/logs/RaupenLog.log +src/main/resources/output/CompilerInput.class +src/test/resources/output/javac/CompilerInput$Test.class +src/test/resources/output/javac/CompilerInput.class +src/test/resources/output/raupenpiler/CompilerInput.class +src/test/resources/output/raupenpiler/CompilerInput$Test.class diff --git a/antlr-4.12.0-complete.jar b/.lib/antlr-4.12.0-complete.jar similarity index 100% rename from antlr-4.12.0-complete.jar rename to .lib/antlr-4.12.0-complete.jar diff --git a/pom.xml b/pom.xml index d81162c..99e9904 100644 --- a/pom.xml +++ b/pom.xml @@ -4,13 +4,14 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - org.example + de.dhbw-stuttgart JavaCompiler - 1.0-SNAPSHOT + 1.0 - 21 - 21 + 22 + ${java.version} + ${java.version} UTF-8 @@ -53,7 +54,28 @@ maven-surefire-plugin 3.0.0-M5 + + maven-assembly-plugin + + + make-assembly + package + + single + + + + + + + main.Main + + + + jar-with-dependencies + + + - \ No newline at end of file diff --git a/src/main/java/Main.java b/src/main/java/Main.java deleted file mode 100644 index 0551ed9..0000000 --- a/src/main/java/Main.java +++ /dev/null @@ -1,132 +0,0 @@ -import ast.ASTNode; -import org.antlr.v4.runtime.*; -import ast.ProgramNode; -//import bytecode.ByteCodeGenerator; -import org.antlr.v4.runtime.CharStream; -import org.antlr.v4.runtime.CharStreams; -import org.antlr.v4.runtime.tree.ParseTree; -import org.antlr.v4.runtime.CommonTokenStream; -import parser.astBuilder.ASTBuilder; -import parser.generated.SimpleJavaLexer; -import parser.generated.SimpleJavaParser; -//import semantic.SemanticAnalyzer; - -import java.io.IOException; -import java.nio.file.Paths; - -public class Main { - public static void main(String[] args) throws Exception { - if(args.length > 0) { - - } else { - try { - CharStream codeCharStream = CharStreams.fromPath(Paths.get("src/main/resources/CompilerInput.java")); - parseFile(codeCharStream); - } catch (IOException e) { - System.err.println("Error reading the file: " + e.getMessage()); - } - } - } - - - static void parseFile(CharStream codeCharStream) { - /* ------------------------- Scanner -> tokens ------------------------- */ - SimpleJavaLexer lexer = new SimpleJavaLexer(codeCharStream); - CommonTokenStream tokenStream = new CommonTokenStream(lexer); - - // Printing the tokens -// tokenStream.fill(); -// List tokens = tokenStream.getTokens(); -// System.out.println("-------------------- Scanner -> tokens --------------------"); -// for (Token token : tokens) { -// String tokenType = SimpleJavaLexer.VOCABULARY.getSymbolicName(token.getType()); -// String tokenText = token.getText(); -// // System.out.println("Token Type: " + tokenType + ", Token Text: " + -// // tokenText); -// System.out.println(tokenType + " " + tokenText); -// } -// System.out.println(); - - /* ------------------------- Parser -> Parsetree ------------------------- */ - SimpleJavaParser parser = new SimpleJavaParser(tokenStream); - ParseTree parseTree = parser.program(); // parse the input - - // Printing the parse tree -// System.out.println("-------------------- Parser -> Parsetree --------------------"); -// System.out.println(parseTree.toStringTree(parser)); -// printTree(parseTree, parser, 0); -// System.out.println(); - - /* ------------------------- AST builder -> AST ------------------------- */ - ASTBuilder astBuilder = new ASTBuilder(); - ProgramNode abstractSyntaxTree = (ProgramNode) astBuilder.visit(parseTree); - System.out.println(abstractSyntaxTree); - // Printing the AST -// System.out.println("-------------------- AST builder -> AST --------------------"); -// // System.out.println("AST: " + ast.toString()); -// printAST(abstractSyntaxTree, 0); -// System.out.println(); - - /* - * ------------------------- Semantic Analyzer -> Tast ------------------------- - */ - //SemanticAnalyzer semanticAnalyzer = new SemanticAnalyzer(); - //ProgramNode typedAst = (ProgramNode) semanticAnalyzer.generateTast(abstractSyntaxTree); - - // Printing the Tast - System.out.println("Tast generated"); - - /* - * ------------------------- Bytecode Generator -> Bytecode - * ------------------------- - */ - //ByteCodeGenerator byteCodeGenerator = new ByteCodeGenerator(); - //byteCodeGenerator.generateByteCode(abstractSyntaxTree); - //byteCodeGenerator.visit(typedAst); - System.out.println("Bytecode generated"); - - } - - /** - * This method is used to print the parse tree in a structured format. - * It recursively traverses the tree and prints the rule names and text of the - * nodes. - * - * @param tree The parse tree to be printed. - * @param parser The parser used to parse the input. It's used to get the rule - * names. - * @param indent The current indentation level. It's used to format the output. - */ - public static void printTree(ParseTree tree, Parser parser, int indent) { - // Create an indentation string based on the current indentation level - String indentString = " ".repeat(indent * 2); - - // If the tree node is an instance of RuleContext (i.e., it's an internal node), - // print the rule name - if (tree instanceof RuleContext) { - int ruleIndex = ((RuleContext) tree).getRuleIndex(); - String ruleName = parser.getRuleNames()[ruleIndex]; - System.out.println(indentString + ruleName); - } else { - // If the tree node is not an instance of RuleContext (i.e., it's a leaf node), - // print the text of the node - System.out.println(indentString + tree.getText()); - } - - // Recursively print the children of the current node, increasing the - // indentation level - for (int i = 0; i < tree.getChildCount(); i++) { - printTree(tree.getChild(i), parser, indent + 1); - } - } - - public static void printAST(ASTNode node, int indent) { - String indentString = " ".repeat(indent * 2); - System.out.println(indentString + node.getClass().toString()); - - // for (ASTNode child : node.) { - // printAST(child, indent + 1); - // } - } - -} \ No newline at end of file diff --git a/src/main/java/bytecode/ByteCodeGenerator.java b/src/main/java/bytecode/ByteCodeGenerator.java index d85935a..7db6395 100644 --- a/src/main/java/bytecode/ByteCodeGenerator.java +++ b/src/main/java/bytecode/ByteCodeGenerator.java @@ -6,6 +6,12 @@ import bytecode.visitor.ProgramVisitor; public class ByteCodeGenerator implements ProgramVisitor { + private final String outputDirectoryPath; + + public ByteCodeGenerator(String outputDirectoryPath) { + this.outputDirectoryPath = outputDirectoryPath; + } + @Override public void visit(ProgramNode programNode) { for (ClassNode classDeclarationNode : programNode.classes) { diff --git a/src/main/java/bytecode/ClassCodeGen.java b/src/main/java/bytecode/ClassCodeGen.java index c911199..d6e249d 100644 --- a/src/main/java/bytecode/ClassCodeGen.java +++ b/src/main/java/bytecode/ClassCodeGen.java @@ -6,7 +6,9 @@ import ast.member.MemberNode; import ast.member.MethodNode; import ast.type.type.BaseType; import bytecode.visitor.ClassVisitor; + import java.io.File; + import org.objectweb.asm.ClassWriter; import java.io.FileOutputStream; @@ -16,8 +18,10 @@ import java.io.IOException; public class ClassCodeGen implements ClassVisitor { private Mapper mapper; private ClassWriter classWriter; + private final String outputDirectoryPath; - public ClassCodeGen() { + public ClassCodeGen(String outputDirectoryPath) { + this.outputDirectoryPath = outputDirectoryPath; mapper = new Mapper(); } @@ -51,13 +55,14 @@ public class ClassCodeGen implements ClassVisitor { } private void printIntoClassFile(byte[] byteCode, String name) { - String directoryPath = "src/main/java/classFileOutput"; - File directory = new File(directoryPath); + // String outputDirectoryPath = "src/main/resources/output"; + // System.out.println("Output directory path: " + outputDirectoryPath); + File directory = new File(outputDirectoryPath); if (!directory.exists()) { directory.mkdirs(); } - String filePath = directoryPath + "/" + name + ".class"; + String filePath = outputDirectoryPath + "/" + name + ".class"; try { FileOutputStream fileOutputStream = new FileOutputStream(filePath); fileOutputStream.write(byteCode); diff --git a/src/main/java/bytecode/visitor/ClassVisitor.java b/src/main/java/bytecode/visitor/ClassVisitor.java index 903775a..078f211 100644 --- a/src/main/java/bytecode/visitor/ClassVisitor.java +++ b/src/main/java/bytecode/visitor/ClassVisitor.java @@ -4,6 +4,7 @@ import ast.ClassNode; import ast.member.FieldNode; public interface ClassVisitor { - void visit(ClassNode classNode); - void visit(FieldNode fieldNode); + void visit(ClassNode classNode); + + void visit(FieldNode fieldNode); } diff --git a/src/main/java/classFileOutput/Example.class b/src/main/java/classFileOutput/Example.class deleted file mode 100644 index e69de29..0000000 diff --git a/src/main/java/classFileOutput/Test.class b/src/main/java/classFileOutput/Test.class deleted file mode 100644 index 98f2799..0000000 Binary files a/src/main/java/classFileOutput/Test.class and /dev/null differ diff --git a/src/main/java/main/Main.java b/src/main/java/main/Main.java new file mode 100644 index 0000000..8b858b4 --- /dev/null +++ b/src/main/java/main/Main.java @@ -0,0 +1,108 @@ +package main; + +import ast.ASTNode; +import ast.ProgramNode; +import parser.ASTBuilder; +import parser.generated.SimpleJavaLexer; +import parser.generated.SimpleJavaParser; +import semantic.SemanticAnalyzer; +import bytecode.ByteCodeGenerator; + +import org.antlr.v4.runtime.*; +import org.antlr.v4.runtime.tree.ParseTree; + +import java.io.IOException; +import java.nio.file.Paths; + + +/** + * Start Raupenpiler using make: + *

cd .\src\test\ + *

make clean compile-raupenpiler + *

Start Raupenpiler using jar: + *

java.exe -jar path_to_jar\JavaCompiler-1.0-SNAPSHOT-jar-with-dependencies.jar 'path_to_input_file.java' 'path_to_output_directory' + *

Example (jar needs to be in the target directory, compile with make or mvn package first): + * java.exe -jar .\target\JavaCompiler-1.0-SNAPSHOT-jar-with-dependencies.jar 'src/main/resources/input/CompilerInput.java' 'src/main/resources/output' + */ +public class Main { + + + public static void main(String[] args) throws Exception { + if (args.length == 2) { + // args[0] is the input file path + // args[1] is the output directory path + String inputFilePath = args[0]; + String outputDirectoryPath = args[1]; + System.out.println("Compiling file: " + inputFilePath); + try { + CharStream inputCharStream = CharStreams.fromPath(Paths.get(inputFilePath)); + compileFile(inputCharStream, outputDirectoryPath); + } catch (IOException e) { + System.err.println("Error reading the file: " + e.getMessage()); + } + } + /* !!! Else Branch (main ohne args starten) ist nicht zur Verwendung vorgesehen, immer mit args starten !!! + else { + try { + CharStream codeCharStream = CharStreams.fromPath(Paths.get("src/main/resources/input/CompilerInput.java")); + compileFile(codeCharStream); + } catch (IOException e) { + System.err.println("Error reading the file: " + e.getMessage()); + } + } + */ + } + + /** + * This method is used to compile a file from a given CharStream and output the bytecode to a specified directory. + * It goes through the following steps: + *

1. Scanner: It uses the SimpleJavaLexer to tokenize the input CharStream. + *

2. Parser: It uses the SimpleJavaParser to parse the tokens and generate a ParseTree. + *

3. AST Builder: It uses the ASTBuilder to visit the ParseTree and generate an Abstract Syntax Tree (AST). + *

4. Semantic Analyzer: It uses the SemanticAnalyzer to generate a typed AST. + *

5. Bytecode Generator: It uses the ByteCodeGenerator to generate bytecode from the typed AST and output it to the specified directory. + * + * @param inputCharStream The CharStream representing the input file to be compiled. + * @param outputDirectoryPath The path of the directory where the output bytecode should be written. + */ + static void compileFile(CharStream inputCharStream, String outputDirectoryPath) { + // Initialize the logger + new RaupenLogger(); + + /* ------------------------- Scanner -> tokens ------------------------- */ + // Use the SimpleJavaLexer to tokenize the input CharStream + SimpleJavaLexer lexer = new SimpleJavaLexer(inputCharStream); + CommonTokenStream tokenStream = new CommonTokenStream(lexer); + tokenStream.fill(); + // Log the tokens + RaupenLogger.logScanner(tokenStream); + + /*------------------------- Parser -> Parsetree -------------------------*/ + // Use the SimpleJavaParser to parse the tokens and generate a ParseTree + SimpleJavaParser parser = new SimpleJavaParser(tokenStream); + ParseTree parseTree = parser.program(); // parse the input + // Log the ParseTree + RaupenLogger.logParser(parseTree, parser); + + /*------------------------- AST builder -> AST -------------------------*/ + // Use the ASTBuilder to visit the ParseTree and generate an Abstract Syntax Tree (AST) + ASTBuilder astBuilder = new ASTBuilder(); + ASTNode abstractSyntaxTree = astBuilder.visit(parseTree); + // Log the AST + RaupenLogger.logAST(abstractSyntaxTree); + + /*------------------------- Semantic Analyzer -> typed AST -------------------------*/ + // Use the SemanticAnalyzer to generate a typed AST + ASTNode typedAst = SemanticAnalyzer.generateTast(abstractSyntaxTree); + // Log the typed AST + RaupenLogger.logSemanticAnalyzer(typedAst); + + /*------------------------- Bytecode Generator -> Bytecode -------------------------*/ + // Use the ByteCodeGenerator to generate bytecode from the typed AST and output it to the specified directory + ByteCodeGenerator byteCodeGenerator = new ByteCodeGenerator(outputDirectoryPath); + assert typedAst != null; + byteCodeGenerator.visit((ProgramNode) typedAst); + // Log the bytecode generation + RaupenLogger.logBytecodeGenerator(); + } +} \ No newline at end of file diff --git a/src/main/java/main/RaupenLogger.java b/src/main/java/main/RaupenLogger.java new file mode 100644 index 0000000..4ea499f --- /dev/null +++ b/src/main/java/main/RaupenLogger.java @@ -0,0 +1,180 @@ +package main; + +import ast.ASTNode; +import org.antlr.v4.runtime.CommonTokenStream; +import org.antlr.v4.runtime.Parser; +import org.antlr.v4.runtime.RuleContext; +import org.antlr.v4.runtime.Token; +import org.antlr.v4.runtime.tree.ParseTree; +import parser.generated.SimpleJavaLexer; +import parser.generated.SimpleJavaParser; + +import java.io.IOException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.List; +import java.util.logging.*; + +/** + Beispiel für Logging-Arten: +

logger.severe("Schwerwiegender Fehler"); +

logger.warning("Warnung"); +

logger.info("Information"); +

logger.config("Konfigurationshinweis"); +

logger.fine("Fein"); +

logger.finer("Feiner"); +

logger.finest("Am feinsten"); +

You may toggle the logging level of the console and file handlers by + changing the level ALL/OFF/etc. in the constructor. + consoleHandler.setLevel(Level.OFF); + fileHandler.setLevel(Level.ALL); + */ +public class RaupenLogger { + + static Logger logger = Logger.getLogger("RaupenLogs"); + + public RaupenLogger() { + // ------------------------- Logging ------------------------- + logger.setLevel(Level.ALL); + logger.getParent().getHandlers()[0].setLevel(Level.ALL); + logger.setUseParentHandlers(false); + + // Custom formatter class + class CustomFormatter extends Formatter { + private final SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss dd-MM-yyyy"); + + @Override + public String format(LogRecord record) { + return formatMessage(record) + System.lineSeparator(); + } + + @Override + public String getHead(Handler h) { + Date now = new Date(); + String dateTime = dateFormat.format(now); + return "Log Start Time: " + dateTime + "\n" + + "Logger Name: " + h.getFormatter().getClass().getName() + "\n\n"; + } + } + + try { + // Configure console handler + Handler consoleHandler = new ConsoleHandler(); + // Toggle console logging on/off + consoleHandler.setLevel(Level.OFF); + consoleHandler.setFormatter(new CustomFormatter()); + logger.addHandler(consoleHandler); + + // Configure file handler + Handler fileHandler = new FileHandler("src/main/resources/logs/RaupenLog.log"); + // Toggle file logging on/off + fileHandler.setLevel(Level.ALL); + fileHandler.setFormatter(new CustomFormatter()); + logger.addHandler(fileHandler); + + } catch (SecurityException | IOException e) { + e.printStackTrace(); + } + } + + public static void logScanner(CommonTokenStream tokenStream) { + // Printing the tokens + logger.info("-------------------- Scanner -> Tokens --------------------"); + List tokens = tokenStream.getTokens(); + for (Token token : tokens) { + String tokenType = + SimpleJavaLexer.VOCABULARY.getSymbolicName(token.getType()); + String tokenText = token.getText(); + // logger.info("Token Type: " + tokenType + ", Token Text: " + tokenText); + logger.info(tokenType + " " + tokenText); + } + logger.info("\n"); + } + + public static void logParser(ParseTree parseTree, SimpleJavaParser parser) { + // Printing the parse tree + logger.info("-------------------- Parser -> Parsetree --------------------"); + logger.info(parseTree.toStringTree(parser)); //one line representation + logTree(parseTree, parser, 0); + logger.info("\n"); + } + + public static void logAST(ASTNode abstractSyntaxTree) { + // Printing the AST + logger.info("-------------------- AST builder -> AST --------------------"); + // logger.info("AST: " + ast.toString()); + logAST(abstractSyntaxTree, 0); + logger.info("\n"); + } + + public static void logSemanticAnalyzer(ASTNode typedAst) { + // Printing the typed AST + logger.info("-------------------- Semantic Analyzer -> typed AST --------------------"); + logAST(typedAst, 0); + logger.info("\n"); + } + + public static void logBytecodeGenerator() { + // Printing the bytecode + logger.info("-------------------- Bytecode Generator -> Bytecode --------------------"); + logger.info("Bytecode generated"); + logger.info("\n"); + } + + + + + + + + + + /* ------------------------- Printing methods ------------------------- */ + + /** + * This method is used to print the parse tree in a structured format. + * It recursively traverses the tree and prints the rule names and text of the + * nodes. + * + * @param tree The parse tree to be printed. + * @param parser The parser used to parse the input. It's used to get the rule + * names. + * @param indent The current indentation level. It's used to format the output. + */ + public static void logTree(ParseTree tree, Parser parser, int indent) { + // Create an indentation string based on the current indentation level + String indentString = " ".repeat(indent * 2); + + // If the tree node is an instance of RuleContext (i.e., it's an internal node), + // print the rule name + if (tree instanceof RuleContext) { + int ruleIndex = ((RuleContext) tree).getRuleIndex(); + String ruleName = parser.getRuleNames()[ruleIndex]; + logger.info(indentString + ruleName); + } else { + // If the tree node is not an instance of RuleContext (i.e., it's a leaf node), + // print the text of the node + logger.info(indentString + tree.getText()); + } + + // Recursively print the children of the current node, increasing the + // indentation level + for (int i = 0; i < tree.getChildCount(); i++) { + logTree(tree.getChild(i), parser, indent + 1); + } + } + + // TODO: Fix this method + public static void logAST(ASTNode abstractSyntaxTree, int indent) { + if (abstractSyntaxTree == null) { + logger.severe("AST is null !!!"); + return; + } + String indentString = " ".repeat(indent * 2); + logger.info(indentString + abstractSyntaxTree.getClass()); + + // for (ASTNode child : node.) { + // printAST(child, indent + 1); + // } + } +} diff --git a/src/main/resources/CompilerInput.java b/src/main/resources/CompilerInput.java deleted file mode 100644 index ba8a8e5..0000000 --- a/src/main/resources/CompilerInput.java +++ /dev/null @@ -1,17 +0,0 @@ -public class Example { - - public int a; - - public static int testMethod(char x){ - - } - -} - -public class Test { - - public static int testMethod(char x, int a){ - x = x + a; - return x; - } -} \ No newline at end of file diff --git a/src/main/resources/input/CompilerInput.java b/src/main/resources/input/CompilerInput.java new file mode 100644 index 0000000..d850a3e --- /dev/null +++ b/src/main/resources/input/CompilerInput.java @@ -0,0 +1,16 @@ +public class CompilerInput { + + public int a; + + public static int testMethod(char x){ + return 0; + } + + public class Test { + + public static int testMethod(char x, int a){ + return 0; + } + } +} + diff --git a/src/main/test/java/EmptyClassExample.class b/src/main/test/java/EmptyClassExample.class deleted file mode 100644 index 7a73bad..0000000 Binary files a/src/main/test/java/EmptyClassExample.class and /dev/null differ diff --git a/src/main/test/java/Tester.java b/src/main/test/java/Tester.java deleted file mode 100644 index 777c50b..0000000 --- a/src/main/test/java/Tester.java +++ /dev/null @@ -1,11 +0,0 @@ -public class Tester { - public static void main(String[] args) { - new EmptyClassExample(); - // cp mitgeben - } -} -// java -jar pfadtocompiler.jar EmptyClass.java -//mit bash scipt ode rmakefile test automatisieren -//mvn package -// javac tester // tester compilen -// java tester // tester ausführen \ No newline at end of file diff --git a/src/main/test/java/make.md b/src/main/test/java/make.md deleted file mode 100644 index e69de29..0000000 diff --git a/src/test/Makefile b/src/test/Makefile new file mode 100644 index 0000000..e3e7d75 --- /dev/null +++ b/src/test/Makefile @@ -0,0 +1,29 @@ +# Makefile +### IntelliJs play buttons do not work. Run in "src/test" folder with "make" command to run all +### Or run only parts with "make compile-javac", "make clean" etc. + +all: compile-javac compile-raupenpiler + +compile-javac: + javac -d .\resources\output\javac .\resources\input\CompilerInput.java + +compile-raupenpiler: + cd ../.. ; mvn -DskipTests install + cd ../.. ; mvn exec:java -Dexec.mainClass="main.Main" -Dexec.args="'src/main/resources/input/CompilerInput.java' 'src/main/resources/output' " + +test: test-javac test-raupenpiler + +test-javac: + #compile-javac + #java -cp .\resources\output\javac CompilerInput + +test-raupenpiler: + #java -cp .\resources\output\raupenpiler CompilerInput + +clean: + rm -f ./resources/output/javac/*.class + rm -f ./resources/output/raupenpiler/*.class + rm -f ./java/*.class + rm -f ../main/resources/output/*.class + rm -f ../main/resources/logs/*.log + diff --git a/src/main/test/TestSpecs.md b/src/test/TestSpecs.md similarity index 58% rename from src/main/test/TestSpecs.md rename to src/test/TestSpecs.md index 6fd5a41..0911765 100644 --- a/src/main/test/TestSpecs.md +++ b/src/test/TestSpecs.md @@ -1,5 +1,7 @@ # Scanner + ## Scanner Input + ### Beispiel 1: Empty Class String empty class = "public class Name {}"; @@ -15,64 +17,76 @@ "}" ## Scanner Output + +CommonTokenStream + ### Beispiel 1: Empty Class Token Type; Token Text Type gibts nur bei Terminalen, Text bei allen - + [null "public", null "class", IDENTIFIER "Name", null "{", null "}", EOF ""] Bsp von Ihm mal: [TokPublic,TokClass,TokIdentifier "Name",TokLeftBrace,TokRightBrace] -### Beispiel 2: Filled Class - - [TokClass,TokIdentifier "javaFileInput.Example",TokLeftBrace] - [TokIf,TokLeftParen,TokIdentifier "x",TokLessThan,TokNumber 5,TokRightParen,TokLeftBrace] - [TokFor,TokLeftParen,TokIdentifier "int",TokIdentifier "i",TokAssign,TokNumber 0,TokSemicolon,TokIdentifier "i",TokLessThan,TokNumber 10,TokSemicolon,TokIdentifier "i",TokPlus,TokPlus,TokRightParen,TokLeftBrace] - [TokWhile,TokLeftParen,TokIdentifier "true",TokRightParen,TokLeftBrace] - [TokIdentifier "x",TokAssign,TokNumber 5,TokSemicolon] - [TokRightBrace] - # Parser -## Parser Input + +## Parser Input + +CommonTokenStream (Scanner Output) ## Parser Output (AST) + +(program (classDeclaration (accessType public) class Name { })) + +ParseTree + ### Beispiel 1: Empty Class - - -### Beispiel 2: Filled Class - - - # Semantische Analyse / Typcheck -## Typcheck Input + +## Typcheck Input + (Parser Output = AST) ## Typcheck Output ### Beispiel 1: Empty Class - - -### Beispiel 2: Filled Class - - # Bytecodegenerierung -## Bytecodegenerierung Input + +## Bytecodegenerierung Input + (Typcheck Output = vom Typcheck eventuell manipulierter AST) ## Bytecodegenerierung Output ### Beispiel 1: Empty Class + Compiled Classfile public class javaFileInput.Example { } +## E2E Tests: +- Testdatei mit Main ausführen/kompilieren +- Testdatei mit "javac -d output .\CompilerInput.java" kompilieren +- -> Dateien mit javap vergleichen -### Beispiel 2: Filled Class - \ No newline at end of file +wenn beides erfolgreich + +- Ergebnis vom eigenen Compiler mithilfe von main.TestCompilerOutput ausführen +- (Ergebnis von javac mithilfe von main.TestCompilerOutput ausführen) + +### Andis Tipps: + +- cp mitgeben +- makefile +- java -jar pfadtocompiler.jar EmptyClass.java +- mvn package +- javac tester // tester compilen +- java tester // tester ausführen +- -> tester ist in unserem Fall main.TestCompilerOutput.java \ No newline at end of file diff --git a/src/main/test/java/EmptyClassExample.java b/src/test/java/main/EmptyClassExample.java similarity index 65% rename from src/main/test/java/EmptyClassExample.java rename to src/test/java/main/EmptyClassExample.java index 9f54ec6..e7715be 100644 --- a/src/main/test/java/EmptyClassExample.java +++ b/src/test/java/main/EmptyClassExample.java @@ -1,3 +1,5 @@ +package main; + public class EmptyClassExample { private class Inner { } diff --git a/src/main/test/java/FailureTest.java b/src/test/java/main/FailureTest.java similarity index 68% rename from src/main/test/java/FailureTest.java rename to src/test/java/main/FailureTest.java index bc63d91..5a2e1c8 100644 --- a/src/main/test/java/FailureTest.java +++ b/src/test/java/main/FailureTest.java @@ -1,3 +1,5 @@ +package main; + import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -15,17 +17,17 @@ import java.util.List; public class FailureTest { private static final List TEST_FILES = Arrays.asList( - "src/main/test/resources/failureTests/TestClass1.java", - "src/main/test/resources/failureTests/TestClass2.java", - "src/main/test/resources/failureTests/TestClass3.java", - "src/main/test/resources/failureTests/TestClass4.java", - "src/main/test/resources/failureTests/TestClass5.java", - "src/main/test/resources/failureTests/TestClass6.java", - "src/main/test/resources/failureTests/TestClass7.java", - "src/main/test/resources/failureTests/TestClass8.java", - "src/main/test/resources/failureTests/TestClass9.java", - "src/main/test/resources/failureTests/TestClass10.java", - "src/main/test/resources/failureTests/TestClass11.java" + "src/main/test/resources/input/failureTests/TestClass1.java", + "src/main/test/resources/input/failureTests/TestClass2.java", + "src/main/test/resources/input/failureTests/TestClass3.java", + "src/main/test/resources/input/failureTests/TestClass4.java", + "src/main/test/resources/input/failureTests/TestClass5.java", + "src/main/test/resources/input/failureTests/TestClass6.java", + "src/main/test/resources/input/failureTests/TestClass7.java", + "src/main/test/resources/input/failureTests/TestClass8.java", + "src/main/test/resources/input/failureTests/TestClass9.java", + "src/main/test/resources/input/failureTests/TestClass10.java", + "src/main/test/resources/input/failureTests/TestClass11.java" ); /** @@ -62,8 +64,8 @@ public class FailureTest { void typedASTTest() throws IOException { CharStream codeCharStream = null; try { - codeCharStream = CharStreams.fromPath(Paths.get("src/main/test/resources/EmptyClassExample.java")); - Main.parsefile(codeCharStream); + codeCharStream = CharStreams.fromPath(Paths.get("src/main/test/resources/main/EmptyClassExample.java")); + Main.compileFile(codeCharStream, "src/main/test/resources/output"); } catch (IOException e) { System.err.println("Error reading the file: " + e.getMessage()); } diff --git a/src/main/test/java/MainTest.java b/src/test/java/main/MainTest.java similarity index 65% rename from src/main/test/java/MainTest.java rename to src/test/java/main/MainTest.java index d4899fd..363fa35 100644 --- a/src/main/test/java/MainTest.java +++ b/src/test/java/main/MainTest.java @@ -1,12 +1,8 @@ +package main; + import org.junit.jupiter.api.Test; import org.antlr.v4.runtime.CharStream; import org.antlr.v4.runtime.CharStreams; -import org.antlr.v4.runtime.CommonTokenStream; -import org.antlr.v4.runtime.tree.ParseTree; -import parser.ASTBuilder; -import oldAst.ClassNode; -import oldAst.ProgramNode; -import bytecode.ByteCodeGenerator; import java.io.IOException; import java.nio.file.Paths; @@ -21,8 +17,8 @@ public class MainTest { void testEmptyClass() { CharStream codeCharStream = null; try { - codeCharStream = CharStreams.fromPath(Paths.get("src/main/test/resources/EmptyClassExample.java")); - Main.parsefile(codeCharStream); + codeCharStream = CharStreams.fromPath(Paths.get("src/main/test/resources/CompilerInput.java")); + Main.compileFile(codeCharStream, "src/main/test/resources/output"); } catch (IOException e) { System.err.println("Error reading the file: " + e.getMessage()); } diff --git a/src/test/java/main/TestCompilerOutput.java b/src/test/java/main/TestCompilerOutput.java new file mode 100644 index 0000000..6a30e14 --- /dev/null +++ b/src/test/java/main/TestCompilerOutput.java @@ -0,0 +1,45 @@ +package main; + +/** + * This class is used to test the output of the compiler. + * + *

Im gleichen Ordner wie diese Datei (main.TestCompilerOutput.java) muss die selbst kompilierte CompilerInput.class Datei sein. + *
Hinweis: Diese muss man also vom Ordner main/resources/output in diesen Ordner hier (test/java) rein kopieren. (bis es eine bessere Lösung gibt)

+ * + *

Die selbst kompilierte .class Datei wird dann hier drin geladen und eine Instanz von ihr erstellt, es können auch Methoden aufgerufen werden. + *

Diese main.TestCompilerOutput.java Datei wird dann in \src\test\java> mit javac .\main.TestCompilerOutput.java kompiliert und mit java main.TestCompilerOutput ausgeführt. + * Wenn unser Compiler funktioniert, sollten keine Errors kommen (sondern nur die Ausgaben, die wir in der CompilerInput.java Datei gemacht haben, + * oder Methoden, die wir hier aufrufen).

+ * + *

PROBLEM: Hier kommen Errors, was eigentlich heißt, dass der Compiler nicht funktioniert, der Test sollte eigentlich passen. + *
DENN: Wenn ich statt unserem CompilerInput.class die CompilerInput.class von javac verwende (aus src/test/resources/output/javac ), dann funktioniert es.

+ */ +public class TestCompilerOutput { + public static void main(String[] args) { + try { + // Try to load the class named "CompilerInput" + Class cls = Class.forName("CompilerInput"); + // Print a success message if the class is loaded successfully + System.out.println("Class loaded successfully: " + cls.getName()); + + // Try to create an instance of the loaded class + Object instance = cls.getDeclaredConstructor().newInstance(); + // Print a success message if the instance is created successfully + System.out.println("Instance created: " + instance); + + + // If the class has a main method, you can invoke it + // cls.getMethod("main", String[].class).invoke(null, (Object) new String[]{}); + + // If the class has other methods, you can invoke them as well + // Example: cls.getMethod("someMethod").invoke(instance); + + } catch (ClassNotFoundException e) { + // Print an error message if the class is not found + System.err.println("Class not found: " + e.getMessage()); + } catch (Exception e) { + // Print an error message if any other exception occurs during class loading or instance creation + System.err.println("Error during class loading or execution: " + e.getMessage()); + } + } +} diff --git a/src/test/java/parser/ParserTest.java b/src/test/java/parser/ParserTest.java new file mode 100644 index 0000000..d599632 --- /dev/null +++ b/src/test/java/parser/ParserTest.java @@ -0,0 +1,184 @@ +package parser; + +import org.antlr.v4.runtime.*; +import org.antlr.v4.runtime.tree.ParseTree; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import parser.generated.SimpleJavaLexer; +import parser.generated.SimpleJavaParser; + +import static org.junit.jupiter.api.Assertions.*; + +import java.util.*; + +public class ParserTest { + @BeforeEach + public void init() { // noch nicht benötigt + String inputFilePath = "src/main/resources/input/CompilerInput.java"; + String outputDirectoryPath = "src/main/resources/output"; + } + + /** + * This test method is used to test the scanner functionality of the SimpleJavaLexer. + * It creates a CharStream from a string representing a simple Java class declaration, + * and uses the SimpleJavaLexer to tokenize this input. + * It then compares the actual tokens and their types produced by the lexer to the expected tokens and their types. + */ + @Test + public void scannerTest() { + // Create a CharStream from a string representing a simple Java class declaration + CharStream inputCharStream = CharStreams.fromString("public class Name {}"); + + // Use the SimpleJavaLexer to tokenize the input + SimpleJavaLexer lexer = new SimpleJavaLexer(inputCharStream); + CommonTokenStream tokenStream = new CommonTokenStream(lexer); + tokenStream.fill(); + + // Prepare the expected results + List actualTokens = tokenStream.getTokens(); + List expectedTokens = Arrays.asList("public", "class", "Name", "{", "}", ""); + List expectedTokenTypes = Arrays.asList(null, null, "IDENTIFIER", null, null, "EOF"); + + // Compare the actual tokens and their types to the expected tokens and their types + assertEquals(expectedTokens.size(), actualTokens.size()); + for (int i = 0; i < expectedTokens.size(); i++) { + assertEquals(expectedTokens.get(i), actualTokens.get(i).getText()); + assertEquals(expectedTokenTypes.get(i), SimpleJavaLexer.VOCABULARY.getSymbolicName(actualTokens.get(i).getType())); + } + } + + + @Test + public void parserTest() { + // init + CharStream inputCharStream = CharStreams.fromString("public class Name {}"); + SimpleJavaLexer lexer = new SimpleJavaLexer(inputCharStream); + CommonTokenStream tokenStream = new CommonTokenStream(lexer); + tokenStream.fill(); + + + /* Parser -> Parsetree */ + SimpleJavaParser parser = new SimpleJavaParser(tokenStream); + ParseTree parseTree = parser.program(); // parse the input + + //Variante 1 (geht) + String actualParseTreeAsString = parseTree.toStringTree(parser); + String expectedParseTreeAsString = "(program (classDeclaration (accessType public) class Name { }))"; + + assertEquals(actualParseTreeAsString, expectedParseTreeAsString); + + //Variante 2 (geht nicht) + // - Sollte es gehen und es liegt am Parser? (keine Ahnung) -> Bitte Fehler (actual und expected) durchlesen + Map actualTreeStructure = buildTreeStructure(parseTree, parser); + Map expectedTreeStructure = parseStringToTree(expectedParseTreeAsString); + + assertEquals(actualTreeStructure, expectedTreeStructure); + + + } + + @Test + public void astBuilderTest() { + // TODO: Implement this test method + + + + + /* AST builder -> AST */ + ASTBuilder astBuilder = new ASTBuilder(); + // ProgramNode abstractSyntaxTree = (ProgramNode) astBuilder.visit(parseTree); + + //String actualASTasString = new ASTBuilder().visit(parseTree).toString(); + + // ProgramNode actualAST = new ASTBuilder().visit(parseTree); + // ProgramNode expectedAST = new ProgramNode(); + // expectedAST.add(new ProgramNode.ClassNode("Name", new ProgramNode())); + } + + + // Helpers Variante 2.1 + + public static Map buildTreeStructure(ParseTree tree, Parser parser) { + return buildTree(tree, parser, 0); + } + + private static Map buildTree(ParseTree tree, Parser parser, int indent) { + Map node = new HashMap<>(); + + if (tree instanceof RuleContext) { + int ruleIndex = ((RuleContext) tree).getRuleIndex(); + String ruleName = parser.getRuleNames()[ruleIndex]; + node.put("rule", ruleName); + } else { + node.put("text", tree.getText()); + } + + List> children = new ArrayList<>(); + for (int i = 0; i < tree.getChildCount(); i++) { + children.add(buildTree(tree.getChild(i), parser, indent + 1)); + } + + if (!children.isEmpty()) { + node.put("children", children); + } + + return node; + } + + // Helpers Variante 2.2 + + public static Map parseStringToTree(String input) { + input = input.trim(); + if (input.startsWith("(") && input.endsWith(")")) { + input = input.substring(1, input.length() - 1).trim(); + } + return parse(input); + } + + private static Map parse(String input) { + Map node = new HashMap<>(); + StringBuilder currentToken = new StringBuilder(); + List> children = new ArrayList<>(); + + int depth = 0; + boolean inToken = false; + for (char ch : input.toCharArray()) { + if (ch == '(') { + if (depth == 0) { + if (currentToken.length() > 0) { + node.put("node", currentToken.toString().trim()); + currentToken.setLength(0); + } + } else { + currentToken.append(ch); + } + depth++; + } else if (ch == ')') { + depth--; + if (depth == 0) { + children.add(parse(currentToken.toString().trim())); + currentToken.setLength(0); + } else { + currentToken.append(ch); + } + } else if (Character.isWhitespace(ch) && depth == 0) { + if (currentToken.length() > 0) { + node.put("node", currentToken.toString().trim()); + currentToken.setLength(0); + } + } else { + currentToken.append(ch); + } + } + + if (currentToken.length() > 0) { + node.put("node", currentToken.toString().trim()); + } + + if (!children.isEmpty()) { + node.put("children", children); + } + + return node; + } +} diff --git a/src/test/java/semantic/SemanticTest.java b/src/test/java/semantic/SemanticTest.java index 7000876..d2d1887 100644 --- a/src/test/java/semantic/SemanticTest.java +++ b/src/test/java/semantic/SemanticTest.java @@ -1,9 +1,26 @@ package semantic; -import ast.ASTNode; +import ast.*; +import ast.expression.BinaryExpressionNode; +import ast.expression.ExpressionNode; +import ast.expression.ExpresssionOperator; +import ast.expression.IdentifierExpressionNode; +import ast.member.FieldNode; +import ast.member.MemberNode; +import ast.member.MethodNode; +import ast.parameter.ParameterListNode; +import ast.parameter.ParameterNode; +import ast.statement.AssignmentStatementNode; +import ast.statement.StatementNode; +import ast.type.AccessTypeNode; +import ast.type.BaseTypeNode; +import ast.type.EnumAccessTypeNode; +import ast.type.EnumTypeNode; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import semantic.exeptions.AlreadyDeclearedException; +import java.util.ArrayList; +import java.util.List; import static org.junit.jupiter.api.Assertions.*; @@ -11,23 +28,34 @@ public class SemanticTest { @Test - public void twoFieldsSameName() { - - ASTNode ast = Mocker.mockTwoSameFields(); + public void alreadyDeclaredLocalFieldVar() { + ProgramNode programNode = new ProgramNode(); + List classList = new ArrayList<>(); + AccessTypeNode accessTypeNode = new AccessTypeNode(EnumAccessTypeNode.PUBLIC); + ClassNode classNode = new ClassNode(accessTypeNode, "testClass"); SemanticAnalyzer semanticAnalyzer = new SemanticAnalyzer(); ASTNode tast = semanticAnalyzer.generateTast(ast); - assertEquals(semanticAnalyzer.errors.size(), 1); - assertInstanceOf(AlreadyDeclearedException.class, semanticAnalyzer.errors.getFirst()); - assertNull(tast); + MemberNode memberNode2 = new FieldNode(accessTypeNode, new BaseTypeNode(EnumTypeNode.INT), "testVar"); + classNode.members.add(memberNode2); + classList.add(classNode); + programNode.classes = classList; + + ASTNode typedAst = SemanticAnalyzer.generateTast(programNode); + + assertEquals(1, SemanticAnalyzer.errors.size()); + assertInstanceOf(AlreadyDeclearedException.class, SemanticAnalyzer.errors.getFirst()); + assertNull(typedAst); } @Test - public void simpleMethod(){ - - ASTNode ast = Mocker.mockSimpleMethod(); + public void shouldWorkWithNoError() { + ProgramNode programNode = new ProgramNode(); + List classList = new ArrayList<>(); + AccessTypeNode accessTypeNode = new AccessTypeNode(EnumAccessTypeNode.PUBLIC); + ClassNode classNode = new ClassNode(accessTypeNode, "testClass"); SemanticAnalyzer semanticAnalyzer = new SemanticAnalyzer(); ASTNode tast = semanticAnalyzer.generateTast(ast); @@ -35,29 +63,63 @@ public class SemanticTest { assertEquals(semanticAnalyzer.errors.size(), 0); assertNotNull(tast); + MemberNode memberNode3 = getMemberNode(accessTypeNode); + classNode.members.add(memberNode3); + + classList.add(classNode); + programNode.classes = classList; + + ASTNode typedAst = SemanticAnalyzer.generateTast(programNode); + + assertEquals(0, SemanticAnalyzer.errors.size()); + assertEquals(programNode, typedAst); } - @Test - public void twoSameMethods(){ - ASTNode ast = Mocker.mockTwoSameMethods(); + /** + * This method is used to create a MemberNode representing a method. + * It first creates a list of ParameterNodes and adds a ParameterNode to it. + * Then, it creates a ParameterListNode using the list of ParameterNodes. + * After that, it creates a list of StatementNodes and adds a StatementNode to it by calling the getStatementNode method. + * Finally, it creates a MethodNode using the provided AccessTypeNode, a BaseTypeNode representing the return type of the method, + * the method name, the ParameterListNode, and the list of StatementNodes, and returns this MethodNode. + * + * @param accessTypeNode The AccessTypeNode representing the access type of the method. + * @return The created MemberNode representing the method. + */ +private static MemberNode getMemberNode(AccessTypeNode accessTypeNode) { + List parameterNodeList = new ArrayList<>(); + ParameterNode parameterNode1 = new ParameterNode(new BaseTypeNode(EnumTypeNode.INT), "param1"); + parameterNodeList.add(parameterNode1); + ParameterListNode parameterListNode = new ParameterListNode(parameterNodeList); - SemanticAnalyzer semanticAnalyzer = new SemanticAnalyzer(); - ASTNode tast = semanticAnalyzer.generateTast(ast); + List statementNodeList = new ArrayList<>(); - assertEquals(1, semanticAnalyzer.errors.size()); - assertInstanceOf(AlreadyDeclearedException.class, semanticAnalyzer.errors.getFirst()); - assertNull(tast); - } - - @Test - public void twoDifferentMethods(){ - ASTNode ast = Mocker.mockTwoDifferentMethods(); - - SemanticAnalyzer semanticAnalyzer = new SemanticAnalyzer(); - ASTNode tast = semanticAnalyzer.generateTast(ast); - - assertEquals(semanticAnalyzer.errors.size(), 0); - assertNotNull(tast); - } + StatementNode statementNode1 = getStatementNode(); + statementNodeList.add(statementNode1); + return new MethodNode(accessTypeNode, new BaseTypeNode(EnumTypeNode.INT), "testVar2", parameterListNode, statementNodeList); +} + + /** + * This method is used to create a StatementNode for an assignment operation. + * It first creates two IdentifierExpressionNodes for 'this' and 'objectVar'. + * Then, it creates a BinaryExpressionNode to represent the operation 'this.objectVar'. + * After that, it creates a LiteralNode to represent the integer value 1. + * Finally, it creates another BinaryExpressionNode to represent the assignment operation 'this.objectVar = 1', + * and wraps this expression in an AssignmentStatementNode. + * + * @return The created AssignmentStatementNode representing the assignment operation 'this.objectVar = 1'. + */ +private static StatementNode getStatementNode() { + ExpressionNode expressionNodeObjectVariableLeft = new IdentifierExpressionNode("this"); + ExpressionNode expressionNodeObjectVariableRight = new IdentifierExpressionNode("objectVar"); + + ExpressionNode expressionNodeLeft = new BinaryExpressionNode(expressionNodeObjectVariableLeft, expressionNodeObjectVariableRight, ExpresssionOperator.DOT); + + ExpressionNode expressionNodeRight = new LiteralNode(1); + + BinaryExpressionNode expressionNode = new BinaryExpressionNode(expressionNodeLeft, expressionNodeRight, ExpresssionOperator.ASSIGNMENT); + + return new AssignmentStatementNode(expressionNode); +} } diff --git a/src/main/test/resources/AllFeaturesClassExample.java b/src/test/resources/input/AllFeaturesClassExample.java similarity index 100% rename from src/main/test/resources/AllFeaturesClassExample.java rename to src/test/resources/input/AllFeaturesClassExample.java diff --git a/src/main/test/resources/CombinedExample.java b/src/test/resources/input/CombinedExample.java similarity index 100% rename from src/main/test/resources/CombinedExample.java rename to src/test/resources/input/CombinedExample.java diff --git a/src/test/resources/input/CompilerInput.java b/src/test/resources/input/CompilerInput.java new file mode 100644 index 0000000..d850a3e --- /dev/null +++ b/src/test/resources/input/CompilerInput.java @@ -0,0 +1,16 @@ +public class CompilerInput { + + public int a; + + public static int testMethod(char x){ + return 0; + } + + public class Test { + + public static int testMethod(char x, int a){ + return 0; + } + } +} + diff --git a/src/main/test/resources/MoreFeaturesClassExample.java b/src/test/resources/input/MoreFeaturesClassExample.java similarity index 100% rename from src/main/test/resources/MoreFeaturesClassExample.java rename to src/test/resources/input/MoreFeaturesClassExample.java diff --git a/src/main/test/resources/failureTests/TestClass1.java b/src/test/resources/input/failureTests/TestClass1.java similarity index 100% rename from src/main/test/resources/failureTests/TestClass1.java rename to src/test/resources/input/failureTests/TestClass1.java diff --git a/src/main/test/resources/failureTests/TestClass10.java b/src/test/resources/input/failureTests/TestClass10.java similarity index 100% rename from src/main/test/resources/failureTests/TestClass10.java rename to src/test/resources/input/failureTests/TestClass10.java diff --git a/src/main/test/resources/failureTests/TestClass11.java b/src/test/resources/input/failureTests/TestClass11.java similarity index 100% rename from src/main/test/resources/failureTests/TestClass11.java rename to src/test/resources/input/failureTests/TestClass11.java diff --git a/src/main/test/resources/failureTests/TestClass2.java b/src/test/resources/input/failureTests/TestClass2.java similarity index 100% rename from src/main/test/resources/failureTests/TestClass2.java rename to src/test/resources/input/failureTests/TestClass2.java diff --git a/src/main/test/resources/failureTests/TestClass3.java b/src/test/resources/input/failureTests/TestClass3.java similarity index 100% rename from src/main/test/resources/failureTests/TestClass3.java rename to src/test/resources/input/failureTests/TestClass3.java diff --git a/src/main/test/resources/failureTests/TestClass4.java b/src/test/resources/input/failureTests/TestClass4.java similarity index 100% rename from src/main/test/resources/failureTests/TestClass4.java rename to src/test/resources/input/failureTests/TestClass4.java diff --git a/src/main/test/resources/failureTests/TestClass5.java b/src/test/resources/input/failureTests/TestClass5.java similarity index 100% rename from src/main/test/resources/failureTests/TestClass5.java rename to src/test/resources/input/failureTests/TestClass5.java diff --git a/src/main/test/resources/failureTests/TestClass6.java b/src/test/resources/input/failureTests/TestClass6.java similarity index 100% rename from src/main/test/resources/failureTests/TestClass6.java rename to src/test/resources/input/failureTests/TestClass6.java diff --git a/src/main/test/resources/failureTests/TestClass7.java b/src/test/resources/input/failureTests/TestClass7.java similarity index 100% rename from src/main/test/resources/failureTests/TestClass7.java rename to src/test/resources/input/failureTests/TestClass7.java diff --git a/src/main/test/resources/failureTests/TestClass8.java b/src/test/resources/input/failureTests/TestClass8.java similarity index 100% rename from src/main/test/resources/failureTests/TestClass8.java rename to src/test/resources/input/failureTests/TestClass8.java diff --git a/src/main/test/resources/failureTests/TestClass9.java b/src/test/resources/input/failureTests/TestClass9.java similarity index 100% rename from src/main/test/resources/failureTests/TestClass9.java rename to src/test/resources/input/failureTests/TestClass9.java diff --git a/src/main/test/resources/featureTests/BooleanOperations.java b/src/test/resources/input/featureTests/BooleanOperations.java similarity index 100% rename from src/main/test/resources/featureTests/BooleanOperations.java rename to src/test/resources/input/featureTests/BooleanOperations.java diff --git a/src/main/test/resources/featureTests/CharManipulation.java b/src/test/resources/input/featureTests/CharManipulation.java similarity index 100% rename from src/main/test/resources/featureTests/CharManipulation.java rename to src/test/resources/input/featureTests/CharManipulation.java diff --git a/src/main/test/resources/featureTests/ConditionalStatements.java b/src/test/resources/input/featureTests/ConditionalStatements.java similarity index 100% rename from src/main/test/resources/featureTests/ConditionalStatements.java rename to src/test/resources/input/featureTests/ConditionalStatements.java diff --git a/src/main/test/resources/featureTests/LoopExamples.java b/src/test/resources/input/featureTests/LoopExamples.java similarity index 100% rename from src/main/test/resources/featureTests/LoopExamples.java rename to src/test/resources/input/featureTests/LoopExamples.java diff --git a/src/main/test/resources/featureTests/MethodOverloading.java b/src/test/resources/input/featureTests/MethodOverloading.java similarity index 100% rename from src/main/test/resources/featureTests/MethodOverloading.java rename to src/test/resources/input/featureTests/MethodOverloading.java