From f59d7e99182f7529f85a741d123d4c1a05d5dd5b Mon Sep 17 00:00:00 2001 From: Lucas <89882946+notbad3500@users.noreply.github.com> Date: Mon, 17 Jun 2024 17:42:50 +0200 Subject: [PATCH] First Tests for Parser, pls check --- src/main/java/Main.java | 11 +- src/test/Makefile | 6 +- src/test/TestSpecs.md | 27 ++-- src/test/java/FailureTest.java | 22 ++-- src/test/java/parser/ParserTest.java | 183 +++++++++++++++++++++++++++ 5 files changed, 212 insertions(+), 37 deletions(-) diff --git a/src/main/java/Main.java b/src/main/java/Main.java index 7174d66..21d9349 100644 --- a/src/main/java/Main.java +++ b/src/main/java/Main.java @@ -49,17 +49,16 @@ public class Main { /* ------------------------- Scanner -> tokens ------------------------- */ SimpleJavaLexer lexer = new SimpleJavaLexer(inputCharStream); CommonTokenStream tokenStream = new CommonTokenStream(lexer); + tokenStream.fill(); // Printing the tokens - tokenStream.fill(); + System.out.println("-------------------- Scanner -> Tokens --------------------"); 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("Token Type: " + tokenType + ", Token Text: " + tokenText); System.out.println(tokenType + " " + tokenText); } System.out.println(); @@ -70,8 +69,8 @@ public class Main { // Printing the parse tree System.out.println("-------------------- Parser -> Parsetree --------------------"); - System.out.println(parseTree.toStringTree(parser)); - printTree(parseTree, parser, 0); + System.out.println(parseTree.toStringTree(parser)); //one line representation + // printTree(parseTree, parser, 0); System.out.println(); /*------------------------- AST builder -> AST -------------------------*/ diff --git a/src/test/Makefile b/src/test/Makefile index 1329f1d..1498d17 100644 --- a/src/test/Makefile +++ b/src/test/Makefile @@ -14,11 +14,11 @@ compile-raupenpiler: test: test-javac test-raupenpiler test-javac: - compile-javac - java -cp .\resources\output\javac CompilerInput + #compile-javac + #java -cp .\resources\output\javac CompilerInput test-raupenpiler: - java -cp .\resources\output\raupenpiler CompilerInput + #java -cp .\resources\output\raupenpiler CompilerInput clean: rm -f ./resources/output/javac/*.class diff --git a/src/test/TestSpecs.md b/src/test/TestSpecs.md index 75f979a..cbdc1f5 100644 --- a/src/test/TestSpecs.md +++ b/src/test/TestSpecs.md @@ -18,6 +18,8 @@ ## Scanner Output +CommonTokenStream + ### Beispiel 1: Empty Class Token Type; Token Text @@ -28,26 +30,20 @@ Type gibts nur bei Terminalen, Text bei allen 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 +CommonTokenStream (Scanner Output) ## Parser Output (AST) -### Beispiel 1: Empty Class +(program (classDeclaration (accessType public) class Name { })) -### Beispiel 2: Filled Class +ParseTree + +### Beispiel 1: Empty Class # Semantische Analyse / Typcheck @@ -59,8 +55,6 @@ Type gibts nur bei Terminalen, Text bei allen ### Beispiel 1: Empty Class -### Beispiel 2: Filled Class - # Bytecodegenerierung ## Bytecodegenerierung Input @@ -76,8 +70,6 @@ Compiled Classfile public class javaFileInput.Example { } -### Beispiel 2: Filled Class - ## E2E Tests: - Testdatei mit Main ausführen/kompilieren @@ -85,13 +77,14 @@ Compiled Classfile - -> Dateien mit javap vergleichen wenn beides erfolgreich + - Ergebnis vom eigenen Compiler mithilfe von TestCompilerOutput ausführen - (Ergebnis von javac mithilfe von TestCompilerOutput ausführen) - ### Andis Tipps: + - cp mitgeben -- makefile +- makefile - java -jar pfadtocompiler.jar EmptyClass.java - mvn package - javac tester // tester compilen diff --git a/src/test/java/FailureTest.java b/src/test/java/FailureTest.java index 028c5d1..f131e33 100644 --- a/src/test/java/FailureTest.java +++ b/src/test/java/FailureTest.java @@ -15,17 +15,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" ); /** diff --git a/src/test/java/parser/ParserTest.java b/src/test/java/parser/ParserTest.java index 834f988..173f1ce 100644 --- a/src/test/java/parser/ParserTest.java +++ b/src/test/java/parser/ParserTest.java @@ -1,4 +1,187 @@ package parser; +import ast.ProgramNode; +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.nio.file.Paths; +import java.util.*; +import java.util.function.BooleanSupplier; + 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; + } }