From b37e0658571782be70364c8915827dacaffbdf60 Mon Sep 17 00:00:00 2001 From: Lucas <89882946+notbad3500@users.noreply.github.com> Date: Tue, 25 Jun 2024 16:41:04 +0200 Subject: [PATCH 01/10] Small changes --- src/main/java/ast/ASTNode.java | 3 -- src/main/java/ast/member/MethodNode.java | 17 ++++---- src/main/java/main/Main.java | 5 ++- src/main/java/main/RaupenLogger.java | 30 ++++++------- src/test/Makefile | 10 +++-- src/test/java/main/EmptyClassExample.java | 6 --- src/test/java/main/TestCompilerOutput.java | 6 +-- src/test/java/parser/ParserTest.java | 50 ++++++++++++++++++++++ 8 files changed, 85 insertions(+), 42 deletions(-) delete mode 100644 src/test/java/main/EmptyClassExample.java diff --git a/src/main/java/ast/ASTNode.java b/src/main/java/ast/ASTNode.java index 3ef48fa..2c43451 100644 --- a/src/main/java/ast/ASTNode.java +++ b/src/main/java/ast/ASTNode.java @@ -3,9 +3,6 @@ package ast; //import java.util.List; public interface ASTNode { - /** - * Please implement this method to return a list of children of each node. - */ // public List getChildren(); } diff --git a/src/main/java/ast/member/MethodNode.java b/src/main/java/ast/member/MethodNode.java index bd67bc4..9cb52b8 100644 --- a/src/main/java/ast/member/MethodNode.java +++ b/src/main/java/ast/member/MethodNode.java @@ -22,8 +22,7 @@ public class MethodNode implements MemberNode, Visitable { public List statements = new ArrayList<>(); - public MethodNode(AccessTypeNode visibility, TypeNode type, String identifier, ParameterListNode parameters, - List statements){ + public MethodNode(AccessTypeNode visibility, TypeNode type, String identifier, ParameterListNode parameters, List statements) { this.visibility = visibility; this.type = type; this.identifier = identifier; @@ -31,18 +30,18 @@ public class MethodNode implements MemberNode, Visitable { this.statements = statements; } - public MethodNode(AccessTypeNode visibility, String identifier){ + public MethodNode(AccessTypeNode visibility, String identifier) { this.visibility = visibility; this.identifier = identifier; } - public boolean isSame(MethodNode methodNode){ + public boolean isSame(MethodNode methodNode) { boolean isSame = false; - if(methodNode.identifier.equals(identifier)){ - if(parameters != null && methodNode.parameters != null){ - if(parameters.parameters.size() == methodNode.parameters.parameters.size()){ - for(int i = 0; i < parameters.parameters.size(); i++){ - if(parameters.parameters.get(i).identifier.equals(methodNode.parameters.parameters.get(i).identifier)){ + if (methodNode.identifier.equals(identifier)) { + if (parameters != null && methodNode.parameters != null) { + if (parameters.parameters.size() == methodNode.parameters.parameters.size()) { + for (int i = 0; i < parameters.parameters.size(); i++) { + if (parameters.parameters.get(i).identifier.equals(methodNode.parameters.parameters.get(i).identifier)) { isSame = true; } } diff --git a/src/main/java/main/Main.java b/src/main/java/main/Main.java index 8b858b4..9a88764 100644 --- a/src/main/java/main/Main.java +++ b/src/main/java/main/Main.java @@ -1,7 +1,10 @@ package main; import ast.ASTNode; +import ast.ClassNode; import ast.ProgramNode; +import ast.type.AccessTypeNode; +import ast.type.EnumAccessTypeNode; import parser.ASTBuilder; import parser.generated.SimpleJavaLexer; import parser.generated.SimpleJavaParser; @@ -25,8 +28,6 @@ import java.nio.file.Paths; * 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 diff --git a/src/main/java/main/RaupenLogger.java b/src/main/java/main/RaupenLogger.java index 4ea499f..90bc7e2 100644 --- a/src/main/java/main/RaupenLogger.java +++ b/src/main/java/main/RaupenLogger.java @@ -16,18 +16,18 @@ 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); + * 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 { @@ -172,9 +172,9 @@ public class RaupenLogger { } String indentString = " ".repeat(indent * 2); logger.info(indentString + abstractSyntaxTree.getClass()); + //for (ASTNode child : abstractSyntaxTree.getChildren()) { + // logAST(child, indent + 1); + // } - // for (ASTNode child : node.) { - // printAST(child, indent + 1); - // } } } diff --git a/src/test/Makefile b/src/test/Makefile index e3e7d75..66c7df6 100644 --- a/src/test/Makefile +++ b/src/test/Makefile @@ -10,15 +10,17 @@ compile-javac: 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' " + cp ../main/resources/output/CompilerInput.class .java/resources/output/raupenpiler -test: test-javac test-raupenpiler +test: compile-javac compile-raupenpiler test-javac test-raupenpiler test-javac: - #compile-javac - #java -cp .\resources\output\javac CompilerInput test-raupenpiler: - #java -cp .\resources\output\raupenpiler CompilerInput + mv ../main/resources/output/CompilerInput.class .java/main/ + cd .java/main/ + + clean: rm -f ./resources/output/javac/*.class diff --git a/src/test/java/main/EmptyClassExample.java b/src/test/java/main/EmptyClassExample.java deleted file mode 100644 index e7715be..0000000 --- a/src/test/java/main/EmptyClassExample.java +++ /dev/null @@ -1,6 +0,0 @@ -package main; - -public class EmptyClassExample { - private class Inner { - } -} // -o für outout \ No newline at end of file diff --git a/src/test/java/main/TestCompilerOutput.java b/src/test/java/main/TestCompilerOutput.java index 6a30e14..202770e 100644 --- a/src/test/java/main/TestCompilerOutput.java +++ b/src/test/java/main/TestCompilerOutput.java @@ -3,11 +3,11 @@ 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)

+ *

Im gleichen Ordner wie diese Datei (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/main) 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. + *

Diese 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).

* diff --git a/src/test/java/parser/ParserTest.java b/src/test/java/parser/ParserTest.java index d599632..a265b30 100644 --- a/src/test/java/parser/ParserTest.java +++ b/src/test/java/parser/ParserTest.java @@ -1,5 +1,18 @@ package parser; +import ast.BlockNode; +import ast.ClassNode; +import ast.LiteralNode; +import ast.ProgramNode; +import ast.expression.ExpressionNode; +import ast.member.FieldNode; +import ast.member.MemberNode; +import ast.member.MethodNode; +import ast.parameter.ParameterListNode; +import ast.parameter.ParameterNode; +import ast.statement.ReturnStatementNode; +import ast.statement.StatementNode; +import ast.type.*; import org.antlr.v4.runtime.*; import org.antlr.v4.runtime.tree.ParseTree; import org.junit.jupiter.api.BeforeEach; @@ -81,6 +94,43 @@ public class ParserTest { public void astBuilderTest() { // TODO: Implement this test method + // ---------------- Aktuellen CompilerInput nachbauen ---------------- + ProgramNode startNode = new ProgramNode(); + // public class CompilerInput {} + ClassNode compilerInputClass = new ClassNode(new AccessTypeNode(EnumAccessTypeNode.PUBLIC), "CompilerInput"); + // public int a; + compilerInputClass.addMember(new FieldNode(new AccessTypeNode(EnumAccessTypeNode.PUBLIC), new BaseTypeNode(EnumTypeNode.INT), "a")); + // public static int testMethod(char x) { return 0; } + compilerInputClass.addMember( + new MethodNode( + new AccessTypeNode(EnumAccessTypeNode.PUBLIC), + new BaseTypeNode(EnumTypeNode.INT), + "testMethod", + new ParameterListNode(List.of(new ParameterNode(new BaseTypeNode(EnumTypeNode.CHAR), "x"))), + List.of(new ReturnStatementNode(new LiteralNode(0))) + )); + + ClassNode testClass = new ClassNode(new AccessTypeNode(EnumAccessTypeNode.PUBLIC), "Test"); + testClass.addMember( + new MethodNode( + new AccessTypeNode(EnumAccessTypeNode.PUBLIC), + new BaseTypeNode(EnumTypeNode.INT), + "testMethod", + new ParameterListNode(List.of(new ParameterNode(new BaseTypeNode(EnumTypeNode.CHAR), "x"), new ParameterNode(new BaseTypeNode(EnumTypeNode.INT), "a"))), + List.of(new ReturnStatementNode(new LiteralNode(0))) + ) + ); + + //compilerInputClass.addClass(testClass); + + startNode.addClass(compilerInputClass); + startNode.addClass(testClass); + + // ---------------- Aktuellen CompilerInput nachbauen ---------------- + + + + From cc6d26e17d3a4514ae000e4905ea6e38c232fa84 Mon Sep 17 00:00:00 2001 From: Lucas <89882946+notbad3500@users.noreply.github.com> Date: Tue, 25 Jun 2024 18:05:26 +0200 Subject: [PATCH 02/10] Tests refactored --- src/main/java/main/Main.java | 6 +- .../java/parser/astBuilder/ASTBuilder.java | 126 +++++++++--------- src/test/java/parser/ParserTest.java | 80 ++++++----- .../input/AllFeaturesClassExample.java | 2 - src/test/resources/input/CombinedExample.java | 2 - .../input/MoreFeaturesClassExample.java | 2 - .../input/featureTests/BooleanOperations.java | 2 - .../input/featureTests/CharManipulation.java | 2 - .../featureTests/ConditionalStatements.java | 2 - .../input/featureTests/LoopExamples.java | 2 - .../input/featureTests/MethodOverloading.java | 2 - 11 files changed, 111 insertions(+), 117 deletions(-) diff --git a/src/main/java/main/Main.java b/src/main/java/main/Main.java index 69de2bc..7568d24 100644 --- a/src/main/java/main/Main.java +++ b/src/main/java/main/Main.java @@ -20,13 +20,11 @@ import java.nio.file.Paths; *

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' + *

java.exe -jar path_to_jar\JavaCompiler-1.0-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' + * java.exe -jar .\target\JavaCompiler-1.0-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 diff --git a/src/main/java/parser/astBuilder/ASTBuilder.java b/src/main/java/parser/astBuilder/ASTBuilder.java index 95ac93c..2ac5c29 100644 --- a/src/main/java/parser/astBuilder/ASTBuilder.java +++ b/src/main/java/parser/astBuilder/ASTBuilder.java @@ -53,7 +53,7 @@ public class ASTBuilder extends SimpleJavaBaseVisitor { @Override public ASTNode visitConstructorDeclaration(SimpleJavaParser.ConstructorDeclarationContext ctx) { ConstructorNode constructorNode = new ConstructorNode(ctx.AccessModifier().getText(), ctx.Identifier().getText(), (BlockNode) visit(ctx.block())); - for(SimpleJavaParser.ParameterContext parameter : ctx.parameterList().parameter()) { + for (SimpleJavaParser.ParameterContext parameter : ctx.parameterList().parameter()) { constructorNode.addParameter((ParameterNode) visit(parameter)); } return constructorNode; @@ -61,18 +61,18 @@ public class ASTBuilder extends SimpleJavaBaseVisitor { @Override public ASTNode visitMethodDeclaration(SimpleJavaParser.MethodDeclarationContext ctx) { - if(ctx.MainMethodDeclaration() != null) { + if (ctx.MainMethodDeclaration() != null) { return new MainMethodNode((BlockNode) visit(ctx.block())); } else { - if(ctx.type() != null) { + if (ctx.type() != null) { MethodNode methodNode = new MethodNode(ctx.AccessModifier().getText(), createTypeNode(ctx.type().getText()), false, ctx.Identifier().getText(), (BlockNode) visit(ctx.block())); - for(SimpleJavaParser.ParameterContext parameter : ctx.parameterList().parameter()) { + for (SimpleJavaParser.ParameterContext parameter : ctx.parameterList().parameter()) { methodNode.addParameter((ParameterNode) visit(parameter)); } return methodNode; } else { MethodNode methodNode = new MethodNode(ctx.AccessModifier().getText(), null, true, ctx.Identifier().getText(), (BlockNode) visit(ctx.block())); - for(SimpleJavaParser.ParameterContext parameter : ctx.parameterList().parameter()) { + for (SimpleJavaParser.ParameterContext parameter : ctx.parameterList().parameter()) { methodNode.addParameter((ParameterNode) visit(parameter)); } return methodNode; @@ -92,19 +92,19 @@ public class ASTBuilder extends SimpleJavaBaseVisitor { @Override public ASTNode visitStatement(SimpleJavaParser.StatementContext ctx) { - if(ctx.returnStatement() != null) { + if (ctx.returnStatement() != null) { return visitReturnStatement(ctx.returnStatement()); - } else if(ctx.localVariableDeclaration() != null) { + } else if (ctx.localVariableDeclaration() != null) { return visitLocalVariableDeclaration(ctx.localVariableDeclaration()); - } else if(ctx.block() != null) { + } else if (ctx.block() != null) { return visitBlock(ctx.block()); - } else if(ctx.whileStatement() != null) { + } else if (ctx.whileStatement() != null) { return visitWhileStatement(ctx.whileStatement()); - } else if(ctx.forStatement() != null) { + } else if (ctx.forStatement() != null) { return visitForStatement(ctx.forStatement()); - } else if(ctx.ifElseStatement() != null) { + } else if (ctx.ifElseStatement() != null) { return visitIfElseStatement(ctx.ifElseStatement()); - } else if(ctx.statementExpression() != null) { + } else if (ctx.statementExpression() != null) { return visitStatementExpression(ctx.statementExpression()); } return null; @@ -123,10 +123,10 @@ public class ASTBuilder extends SimpleJavaBaseVisitor { @Override public ASTNode visitBlock(SimpleJavaParser.BlockContext ctx) { BlockNode blockNode = new BlockNode(); - for(SimpleJavaParser.StatementContext statement : ctx.statement()) { + for (SimpleJavaParser.StatementContext statement : ctx.statement()) { blockNode.addStatement((IStatementNode) visit(statement)); } - if(!blockNode.hasReturnStatement) { + if (!blockNode.hasReturnStatement) { blockNode.addStatement(new ReturnStatementNode(null)); } return blockNode; @@ -139,9 +139,9 @@ public class ASTBuilder extends SimpleJavaBaseVisitor { @Override public ASTNode visitForStatement(SimpleJavaParser.ForStatementContext ctx) { - if(ctx.statementExpression(0) != null) { + if (ctx.statementExpression(0) != null) { return new ForStatementNode((IExpressionNode) visit(ctx.statementExpression(0)), (IExpressionNode) visit(ctx.expression()), (IExpressionNode) visit(ctx.statementExpression(1))); - } else if(ctx.localVariableDeclaration() != null) { + } else if (ctx.localVariableDeclaration() != null) { return new ForStatementNode((IStatementNode) visit(ctx.localVariableDeclaration()), (IExpressionNode) visit(ctx.expression()), (IExpressionNode) visit(ctx.statementExpression(1))); } return null; @@ -149,8 +149,8 @@ public class ASTBuilder extends SimpleJavaBaseVisitor { @Override public ASTNode visitIfElseStatement(SimpleJavaParser.IfElseStatementContext ctx) { - IfElseStatementNode ifElseStatementNode = new IfElseStatementNode((IfStatementNode) visit(ctx.ifStatement())); - for(SimpleJavaParser.ElseStatementContext elseStatement : ctx.elseStatement()) { + IfElseStatementNode ifElseStatementNode = new IfElseStatementNode((IfStatementNode) visit(ctx.ifStatement())); + for (SimpleJavaParser.ElseStatementContext elseStatement : ctx.elseStatement()) { ifElseStatementNode.addElseStatement((ElseStatementNode) visit(elseStatement)); } return ifElseStatementNode; @@ -168,13 +168,13 @@ public class ASTBuilder extends SimpleJavaBaseVisitor { @Override public ASTNode visitStatementExpression(SimpleJavaParser.StatementExpressionContext ctx) { - if(ctx.assign() != null) { + if (ctx.assign() != null) { return visitAssign(ctx.assign()); - } else if(ctx.newDeclaration() != null) { + } else if (ctx.newDeclaration() != null) { return visitNewDeclaration(ctx.newDeclaration()); - } else if(ctx.methodCall() != null) { + } else if (ctx.methodCall() != null) { return visitMethodCall(ctx.methodCall()); - } else if(ctx.crementExpression() != null) { + } else if (ctx.crementExpression() != null) { return visitCrementExpression(ctx.crementExpression()); } return null; @@ -188,7 +188,7 @@ public class ASTBuilder extends SimpleJavaBaseVisitor { @Override public ASTNode visitNewDeclaration(SimpleJavaParser.NewDeclarationContext ctx) { NewDeclarationStatementExpressionNode newDeclarationStatementExpressionNode = new NewDeclarationStatementExpressionNode(ctx.Identifier().getText()); - for(SimpleJavaParser.ExpressionContext expression : ctx.argumentList().expression()) { + for (SimpleJavaParser.ExpressionContext expression : ctx.argumentList().expression()) { newDeclarationStatementExpressionNode.addExpression((IExpressionNode) visit(expression)); } return newDeclarationStatementExpressionNode; @@ -197,10 +197,10 @@ public class ASTBuilder extends SimpleJavaBaseVisitor { @Override public ASTNode visitMethodCall(SimpleJavaParser.MethodCallContext ctx) { MethodCallStatementExpressionNode methodCallStatementExpressionNode = new MethodCallStatementExpressionNode((TargetNode) visit(ctx.target()), ctx.Identifier().getText()); - for(SimpleJavaParser.ChainedMethodContext chainedMethod : ctx.chainedMethod()) { + for (SimpleJavaParser.ChainedMethodContext chainedMethod : ctx.chainedMethod()) { methodCallStatementExpressionNode.addChainedMethod((ChainedMethodNode) visit(chainedMethod)); } - for(SimpleJavaParser.ExpressionContext expression : ctx.argumentList().expression()) { + for (SimpleJavaParser.ExpressionContext expression : ctx.argumentList().expression()) { methodCallStatementExpressionNode.addExpression((IExpressionNode) visit(expression)); } return methodCallStatementExpressionNode; @@ -208,13 +208,13 @@ public class ASTBuilder extends SimpleJavaBaseVisitor { @Override public ASTNode visitTarget(SimpleJavaParser.TargetContext ctx) { - if(ctx.This() != null) { + if (ctx.This() != null) { return new TargetNode(true); - } else if(ctx.memberAccess() != null) { + } else if (ctx.memberAccess() != null) { return new TargetNode((MemberAccessNode) visit(ctx.memberAccess())); - } else if(ctx.newDeclaration() != null) { + } else if (ctx.newDeclaration() != null) { return new TargetNode((NewDeclarationStatementExpressionNode) visit(ctx.newDeclaration())); - } else if(ctx.Identifier() != null) { + } else if (ctx.Identifier() != null) { return new TargetNode(ctx.Identifier().getText()); } return null; @@ -223,7 +223,7 @@ public class ASTBuilder extends SimpleJavaBaseVisitor { @Override public ASTNode visitChainedMethod(SimpleJavaParser.ChainedMethodContext ctx) { ChainedMethodNode chainedMethodNode = new ChainedMethodNode(ctx.Identifier().getText()); - for(SimpleJavaParser.ExpressionContext expression : ctx.argumentList().expression()) { + for (SimpleJavaParser.ExpressionContext expression : ctx.argumentList().expression()) { chainedMethodNode.addExpression((IExpressionNode) visit(expression)); } return chainedMethodNode; @@ -231,9 +231,9 @@ public class ASTBuilder extends SimpleJavaBaseVisitor { @Override public ASTNode visitCrementExpression(SimpleJavaParser.CrementExpressionContext ctx) { - if(ctx.incrementExpression() != null) { + if (ctx.incrementExpression() != null) { return visitIncrementExpression(ctx.incrementExpression()); - } else if(ctx.decrementExpression() != null) { + } else if (ctx.decrementExpression() != null) { return visitDecrementExpression(ctx.decrementExpression()); } return null; @@ -241,9 +241,9 @@ public class ASTBuilder extends SimpleJavaBaseVisitor { @Override public ASTNode visitIncrementExpression(SimpleJavaParser.IncrementExpressionContext ctx) { - if(ctx.prefixIncrementExpression() != null) { + if (ctx.prefixIncrementExpression() != null) { return visitPrefixIncrementExpression(ctx.prefixIncrementExpression()); - } else if(ctx.suffixIncrementExpression() != null) { + } else if (ctx.suffixIncrementExpression() != null) { return visitSuffixIncrementExpression(ctx.suffixIncrementExpression()); } return null; @@ -261,9 +261,9 @@ public class ASTBuilder extends SimpleJavaBaseVisitor { @Override public ASTNode visitDecrementExpression(SimpleJavaParser.DecrementExpressionContext ctx) { - if(ctx.prefixDecrementExpression() != null) { + if (ctx.prefixDecrementExpression() != null) { return visitPrefixDecrementExpression(ctx.prefixDecrementExpression()); - } else if(ctx.suffixDecrementExpression() != null) { + } else if (ctx.suffixDecrementExpression() != null) { return visitSuffixDecrementExpression(ctx.suffixDecrementExpression()); } return null; @@ -281,9 +281,9 @@ public class ASTBuilder extends SimpleJavaBaseVisitor { @Override public ASTNode visitExpression(SimpleJavaParser.ExpressionContext ctx) { - if(ctx.unaryExpression() != null) { + if (ctx.unaryExpression() != null) { return visit(ctx.unaryExpression()); - } else if(ctx.binaryExpression() != null) { + } else if (ctx.binaryExpression() != null) { return visit(ctx.binaryExpression()); } return null; @@ -291,19 +291,19 @@ public class ASTBuilder extends SimpleJavaBaseVisitor { @Override public ASTNode visitUnaryExpression(SimpleJavaParser.UnaryExpressionContext ctx) { - if(ctx.This() != null) { + if (ctx.This() != null) { return new UnaryExpressionNode(ctx.This().getText()); - } else if(ctx.Identifier() != null) { + } else if (ctx.Identifier() != null) { return new UnaryExpressionNode(ctx.Identifier().getText()); - } else if(ctx.memberAccess() != null) { + } else if (ctx.memberAccess() != null) { return new UnaryExpressionNode((MemberAccessNode) visitMemberAccess(ctx.memberAccess())); - } else if(ctx.value() != null) { + } else if (ctx.value() != null) { return new UnaryExpressionNode((ValueNode) visitValue(ctx.value())); - } else if(ctx.notExpression() != null) { + } else if (ctx.notExpression() != null) { return new UnaryExpressionNode((NotExpressionNode) visitNotExpression(ctx.notExpression())); - } else if(ctx.statementExpression() != null) { + } else if (ctx.statementExpression() != null) { return new UnaryExpressionNode((IStatementNode) visitStatementExpression(ctx.statementExpression())); - } else if(ctx.expression() != null) { + } else if (ctx.expression() != null) { return new UnaryExpressionNode((IExpressionNode) visitExpression(ctx.expression())); } return null; @@ -312,7 +312,7 @@ public class ASTBuilder extends SimpleJavaBaseVisitor { @Override public ASTNode visitMemberAccess(SimpleJavaParser.MemberAccessContext ctx) { MemberAccessNode memberAccessNode; - if(ctx.This() != null) { + if (ctx.This() != null) { memberAccessNode = new MemberAccessNode(true); } else { memberAccessNode = new MemberAccessNode(false); @@ -325,13 +325,13 @@ public class ASTBuilder extends SimpleJavaBaseVisitor { @Override public ASTNode visitValue(SimpleJavaParser.ValueContext ctx) { - if(ctx.IntValue() != null) { + if (ctx.IntValue() != null) { return new ValueNode(EnumValueNode.INT_VALUE, ctx.IntValue().getText()); - } else if(ctx.BooleanValue() != null) { + } else if (ctx.BooleanValue() != null) { return new ValueNode(EnumValueNode.BOOLEAN_VALUE, ctx.BooleanValue().getText()); - } else if(ctx.CharValue() != null) { + } else if (ctx.CharValue() != null) { return new ValueNode(EnumValueNode.CHAR_VALUE, ctx.CharValue().getText()); - } else if(ctx.NullValue() != null) { + } else if (ctx.NullValue() != null) { return new ValueNode(EnumValueNode.NULL_VALUE, ctx.NullValue().getText()); } return null; @@ -345,9 +345,9 @@ public class ASTBuilder extends SimpleJavaBaseVisitor { @Override public ASTNode visitBinaryExpression(SimpleJavaParser.BinaryExpressionContext ctx) { - if(ctx.calculationExpression() != null) { + if (ctx.calculationExpression() != null) { return visit(ctx.calculationExpression()); - } else if(ctx.nonCalculationExpression() != null) { + } else if (ctx.nonCalculationExpression() != null) { return visit(ctx.nonCalculationExpression()); } return null; @@ -355,9 +355,9 @@ public class ASTBuilder extends SimpleJavaBaseVisitor { @Override public ASTNode visitCalculationExpression(SimpleJavaParser.CalculationExpressionContext ctx) { - if(ctx.calculationExpression() != null) { + if (ctx.calculationExpression() != null) { return new CalculationExpressionNode((CalculationExpressionNode) visit(ctx.calculationExpression()), ctx.LineOperator().getText(), (DotExpressionNode) visit(ctx.dotExpression())); - } else if(ctx.dotExpression() != null) { + } else if (ctx.dotExpression() != null) { return new CalculationExpressionNode((DotExpressionNode) visit(ctx.dotExpression())); } return null; @@ -365,9 +365,9 @@ public class ASTBuilder extends SimpleJavaBaseVisitor { @Override public ASTNode visitDotExpression(SimpleJavaParser.DotExpressionContext ctx) { - if(ctx.dotExpression() != null) { + if (ctx.dotExpression() != null) { return new DotExpressionNode((DotExpressionNode) visit(ctx.dotExpression()), ctx.DotOperator().getText(), (DotSubstractionExpressionNode) visit(ctx.dotSubtractionExpression())); - } else if(ctx.dotSubtractionExpression() != null) { + } else if (ctx.dotSubtractionExpression() != null) { return new DotExpressionNode((DotSubstractionExpressionNode) visit(ctx.dotSubtractionExpression())); } return null; @@ -375,13 +375,13 @@ public class ASTBuilder extends SimpleJavaBaseVisitor { @Override public ASTNode visitDotSubtractionExpression(SimpleJavaParser.DotSubtractionExpressionContext ctx) { - if(ctx.IntValue() != null) { + if (ctx.IntValue() != null) { return new DotSubstractionExpressionNode(new ValueNode(EnumValueNode.INT_VALUE, ctx.IntValue().getText())); - } else if(ctx.Identifier() != null) { + } else if (ctx.Identifier() != null) { return new DotSubstractionExpressionNode(ctx.Identifier().getText()); - } else if(ctx.memberAccess() != null) { + } else if (ctx.memberAccess() != null) { return new DotSubstractionExpressionNode((MemberAccessNode) visit(ctx.memberAccess())); - } else if(ctx.methodCall() != null && ctx.calculationExpression() != null) { + } else if (ctx.methodCall() != null && ctx.calculationExpression() != null) { return new DotSubstractionExpressionNode((MethodCallStatementExpressionNode) visit(ctx.methodCall()), (CalculationExpressionNode) visit(ctx.calculationExpression())); } return null; @@ -394,15 +394,15 @@ public class ASTBuilder extends SimpleJavaBaseVisitor { @Override public ASTNode visitAssignableExpression(SimpleJavaParser.AssignableExpressionContext ctx) { - if(ctx.Identifier() != null) { + if (ctx.Identifier() != null) { return new AssignableExpressionNode(ctx.Identifier().getText()); - } else if(ctx.memberAccess() != null) { + } else if (ctx.memberAccess() != null) { return new AssignableExpressionNode((MemberAccessNode) visit(ctx.memberAccess())); } return null; } - public ITypeNode createTypeNode(String identifier){ + public ITypeNode createTypeNode(String identifier) { return switch (identifier) { case "int" -> new BaseType(TypeEnum.INT); case "boolean" -> new BaseType(TypeEnum.BOOL); diff --git a/src/test/java/parser/ParserTest.java b/src/test/java/parser/ParserTest.java index a7f1614..c75346c 100644 --- a/src/test/java/parser/ParserTest.java +++ b/src/test/java/parser/ParserTest.java @@ -1,18 +1,11 @@ package parser; -import ast.BlockNode; import ast.ClassNode; -import ast.LiteralNode; import ast.ProgramNode; -import ast.expression.ExpressionNode; import ast.member.FieldNode; -import ast.member.MemberNode; import ast.member.MethodNode; -import ast.parameter.ParameterListNode; import ast.parameter.ParameterNode; import ast.statement.ReturnStatementNode; -import ast.statement.StatementNode; -import ast.type.*; import org.antlr.v4.runtime.*; import org.antlr.v4.runtime.tree.ParseTree; import org.junit.jupiter.api.BeforeEach; @@ -49,9 +42,9 @@ public class ParserTest { 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"); + List expectedTokenTypes = Arrays.asList("AccessModifier", "Class", "Identifier", "OpenCurlyBracket", "ClosedCurlyBracket", "EOF"); + List actualTokens = tokenStream.getTokens(); // Compare the actual tokens and their types to the expected tokens and their types assertEquals(expectedTokens.size(), actualTokens.size()); @@ -76,33 +69,32 @@ public class ParserTest { ParseTree parseTree = parser.program(); // parse the input //Variante 1 (geht) + String expectedParseTreeAsString = "(program (classDeclaration public class Name { }))"; String actualParseTreeAsString = parseTree.toStringTree(parser); - String expectedParseTreeAsString = "(program (classDeclaration (accessType public) class Name { }))"; - assertEquals(actualParseTreeAsString, expectedParseTreeAsString); + assertEquals(expectedParseTreeAsString, actualParseTreeAsString); - //Variante 2 (geht nicht) + // 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); + // ist die Methode parseStringToTree() korrekt? -> (glaub nicht) Map expectedTreeStructure = parseStringToTree(expectedParseTreeAsString); + Map actualTreeStructure = buildTreeStructure(parseTree, parser); - assertEquals(actualTreeStructure, expectedTreeStructure); - - + // assertEquals(expectedTreeStructure, actualTreeStructure); } @Test public void astBuilderTest() { // TODO: Implement this test method - // ---------------- Aktuellen CompilerInput nachbauen ---------------- - ProgramNode startNode = new ProgramNode(); + // ---------------- Alter CompilerInput nachgebaut ---------------- + // ProgramNode startNode = new ProgramNode(); // public class CompilerInput {} - ClassNode compilerInputClass = new ClassNode(new AccessTypeNode(EnumAccessTypeNode.PUBLIC), "CompilerInput"); + // ClassNode compilerInputClass = new ClassNode(new AccessTypeNode(EnumAccessTypeNode.PUBLIC), "CompilerInput"); // public int a; - compilerInputClass.addMember(new FieldNode(new AccessTypeNode(EnumAccessTypeNode.PUBLIC), new BaseTypeNode(EnumTypeNode.INT), "a")); + // compilerInputClass.addMember(new FieldNode(new AccessTypeNode(EnumAccessTypeNode.PUBLIC), new BaseTypeNode(EnumTypeNode.INT), "a")); // public static int testMethod(char x) { return 0; } - compilerInputClass.addMember( + /* compilerInputClass.addMember( new MethodNode( new AccessTypeNode(EnumAccessTypeNode.PUBLIC), new BaseTypeNode(EnumTypeNode.INT), @@ -122,28 +114,48 @@ public class ParserTest { ) ); + */ + //compilerInputClass.addClass(testClass); - startNode.addClass(compilerInputClass); - startNode.addClass(testClass); - - // ---------------- Aktuellen CompilerInput nachbauen ---------------- - + // startNode.addClass(compilerInputClass); + // startNode.addClass(testClass); + // ---------------- Leere Klasse nachgebaut ---------------- + + ProgramNode expectedASTEmptyClass = new ProgramNode(); + + // public class Name {} + ClassNode nameClass = new ClassNode("public", "Name"); + + expectedASTEmptyClass.addClass(nameClass); + // ---------------- Leere Klasse erzeugt ---------------- + // 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 parseTreeEmptyClass = parser.program(); // parse the input /* AST builder -> AST */ ASTBuilder astBuilder = new ASTBuilder(); - // ProgramNode abstractSyntaxTree = (ProgramNode) astBuilder.visit(parseTree); + ProgramNode actualASTEmptyClass = (ProgramNode) new ASTBuilder().visit(parseTreeEmptyClass); - //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())); + // ---------------- Vergleichen ---------------- + + String expectedASTasString = expectedASTEmptyClass.toString(); + String actualASTasString = new ASTBuilder().visit(parseTreeEmptyClass).toString(); + + // Wie vergleiche ich das? + assertEquals(expectedASTasString, actualASTasString); + assertEquals(expectedASTEmptyClass, actualASTEmptyClass); } @@ -196,7 +208,7 @@ public class ParserTest { for (char ch : input.toCharArray()) { if (ch == '(') { if (depth == 0) { - if (currentToken.length() > 0) { + if (!currentToken.isEmpty()) { node.put("node", currentToken.toString().trim()); currentToken.setLength(0); } @@ -213,7 +225,7 @@ public class ParserTest { currentToken.append(ch); } } else if (Character.isWhitespace(ch) && depth == 0) { - if (currentToken.length() > 0) { + if (!currentToken.isEmpty()) { node.put("node", currentToken.toString().trim()); currentToken.setLength(0); } @@ -222,7 +234,7 @@ public class ParserTest { } } - if (currentToken.length() > 0) { + if (!currentToken.isEmpty()) { node.put("node", currentToken.toString().trim()); } diff --git a/src/test/resources/input/AllFeaturesClassExample.java b/src/test/resources/input/AllFeaturesClassExample.java index 69ab631..1a8493d 100644 --- a/src/test/resources/input/AllFeaturesClassExample.java +++ b/src/test/resources/input/AllFeaturesClassExample.java @@ -1,5 +1,3 @@ -package resources; - public class AllFeaturesClassExample { int a; boolean b; diff --git a/src/test/resources/input/CombinedExample.java b/src/test/resources/input/CombinedExample.java index e3dae84..e7e000c 100644 --- a/src/test/resources/input/CombinedExample.java +++ b/src/test/resources/input/CombinedExample.java @@ -1,5 +1,3 @@ -package resources; - public class CombinedExample { int number; boolean flag; diff --git a/src/test/resources/input/MoreFeaturesClassExample.java b/src/test/resources/input/MoreFeaturesClassExample.java index c58b5a2..4f6fbf3 100644 --- a/src/test/resources/input/MoreFeaturesClassExample.java +++ b/src/test/resources/input/MoreFeaturesClassExample.java @@ -1,5 +1,3 @@ -package resources; - public class MoreFeaturesClassExample { int hallo; private class Inner { diff --git a/src/test/resources/input/featureTests/BooleanOperations.java b/src/test/resources/input/featureTests/BooleanOperations.java index 17d4a15..5a1af93 100644 --- a/src/test/resources/input/featureTests/BooleanOperations.java +++ b/src/test/resources/input/featureTests/BooleanOperations.java @@ -1,5 +1,3 @@ -package resources.featureTests; - public class BooleanOperations { boolean flag; diff --git a/src/test/resources/input/featureTests/CharManipulation.java b/src/test/resources/input/featureTests/CharManipulation.java index 7b70ad2..c46c169 100644 --- a/src/test/resources/input/featureTests/CharManipulation.java +++ b/src/test/resources/input/featureTests/CharManipulation.java @@ -1,5 +1,3 @@ -package resources.featureTests; - public class CharManipulation { char letter; diff --git a/src/test/resources/input/featureTests/ConditionalStatements.java b/src/test/resources/input/featureTests/ConditionalStatements.java index 8b26079..73cabda 100644 --- a/src/test/resources/input/featureTests/ConditionalStatements.java +++ b/src/test/resources/input/featureTests/ConditionalStatements.java @@ -1,5 +1,3 @@ -package resources.featureTests; - public class ConditionalStatements { int number; diff --git a/src/test/resources/input/featureTests/LoopExamples.java b/src/test/resources/input/featureTests/LoopExamples.java index 2eb2927..ce323a5 100644 --- a/src/test/resources/input/featureTests/LoopExamples.java +++ b/src/test/resources/input/featureTests/LoopExamples.java @@ -1,5 +1,3 @@ -package resources.featureTests; - public class LoopExamples { public static void main(String[] args) { // For loop example diff --git a/src/test/resources/input/featureTests/MethodOverloading.java b/src/test/resources/input/featureTests/MethodOverloading.java index 3ca1d13..16c9f09 100644 --- a/src/test/resources/input/featureTests/MethodOverloading.java +++ b/src/test/resources/input/featureTests/MethodOverloading.java @@ -1,5 +1,3 @@ -package resources.featureTests; - public class MethodOverloading { public int add(int a, int b) { return a + b; From 34d17660efe1ab15ebd36f2e5eb220ab01e29573 Mon Sep 17 00:00:00 2001 From: Lucas <89882946+notbad3500@users.noreply.github.com> Date: Tue, 25 Jun 2024 18:05:58 +0200 Subject: [PATCH 03/10] Tests refactored --- src/test/resources/input/featureTests/EmptyClassExample.java | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 src/test/resources/input/featureTests/EmptyClassExample.java diff --git a/src/test/resources/input/featureTests/EmptyClassExample.java b/src/test/resources/input/featureTests/EmptyClassExample.java new file mode 100644 index 0000000..f30a941 --- /dev/null +++ b/src/test/resources/input/featureTests/EmptyClassExample.java @@ -0,0 +1,2 @@ +public class EmptyClassExample { +} \ No newline at end of file From eb313464f0f46c7bfc0496c655f51fbe9e56dc61 Mon Sep 17 00:00:00 2001 From: Lucas <89882946+notbad3500@users.noreply.github.com> Date: Wed, 26 Jun 2024 11:25:24 +0200 Subject: [PATCH 04/10] Tests (structure) refactored --- src/test/Makefile | 17 ++- src/test/TestSpecs.md | 7 +- ...ompilerOutput.java => EndToEndTester.java} | 8 +- src/test/java/main/FailureTest.java | 66 ++++------- src/test/java/main/FeatureTest.java | 46 ++++++++ src/test/java/main/MainTest.java | 6 +- src/test/java/parser/AstBuilderTest.java | 103 ++++++++++++++++ src/test/java/parser/ParserTest.java | 111 +----------------- src/test/java/parser/ScannerTest.java | 45 +++++++ 9 files changed, 240 insertions(+), 169 deletions(-) rename src/test/java/main/{TestCompilerOutput.java => EndToEndTester.java} (82%) create mode 100644 src/test/java/main/FeatureTest.java create mode 100644 src/test/java/parser/AstBuilderTest.java create mode 100644 src/test/java/parser/ScannerTest.java diff --git a/src/test/Makefile b/src/test/Makefile index 66c7df6..883b79c 100644 --- a/src/test/Makefile +++ b/src/test/Makefile @@ -15,17 +15,28 @@ compile-raupenpiler: test: compile-javac compile-raupenpiler test-javac test-raupenpiler test-javac: + # gleich wie bei raupenpiler, kann ich ohne funktionierenden Compiler nicht testen + test-raupenpiler: + # move the compiled class to the test/main folder mv ../main/resources/output/CompilerInput.class .java/main/ - cd .java/main/ + # compile the test class + javac .java/main.EndToEndTester.java + # run the test class + java .java/main.EndToEndTester clean: + # clean output folders + rm -f ../main/resources/output/*.class rm -f ./resources/output/javac/*.class rm -f ./resources/output/raupenpiler/*.class - rm -f ./java/*.class - rm -f ../main/resources/output/*.class + # clean logs rm -f ../main/resources/logs/*.log + # clean test/main folders from .class files for End-to-End tests + rm -f ./java/main/*.class + # clean javac output from featureTests + rm -f ./resources/input/featureTests/*.class diff --git a/src/test/TestSpecs.md b/src/test/TestSpecs.md index 0911765..da23e18 100644 --- a/src/test/TestSpecs.md +++ b/src/test/TestSpecs.md @@ -78,8 +78,8 @@ Compiled Classfile wenn beides erfolgreich -- Ergebnis vom eigenen Compiler mithilfe von main.TestCompilerOutput ausführen -- (Ergebnis von javac mithilfe von main.TestCompilerOutput ausführen) +- Ergebnis vom eigenen Compiler mithilfe von main.EndToEndTester ausführen +- (Ergebnis von javac mithilfe von main.EndToEndTester ausführen) ### Andis Tipps: @@ -89,4 +89,5 @@ wenn beides erfolgreich - 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 +- -> tester ist in unserem Fall main.EndToEndTester.java +- -> Hab ich alles umgesetzt \ No newline at end of file diff --git a/src/test/java/main/TestCompilerOutput.java b/src/test/java/main/EndToEndTester.java similarity index 82% rename from src/test/java/main/TestCompilerOutput.java rename to src/test/java/main/EndToEndTester.java index 202770e..233a9c3 100644 --- a/src/test/java/main/TestCompilerOutput.java +++ b/src/test/java/main/EndToEndTester.java @@ -3,18 +3,18 @@ package main; /** * This class is used to test the output of the compiler. * - *

Im gleichen Ordner wie diese Datei (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/main) rein kopieren. (bis es eine bessere Lösung gibt)

+ *

Im gleichen Ordner wie diese Datei (EndToEndTester.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/main) rein kopieren. (bis es eine bessere Lösung gibt -> bin grad in der Make dran das alles hier automatisch zu machen)

* *

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

Diese TestCompilerOutput.java Datei wird dann in \src\test\java> mit javac .\main.TestCompilerOutput.java kompiliert und mit java main.TestCompilerOutput ausgeführt. + *

Diese EndToEndTester.java Datei wird dann in \src\test\java> mit javac .\main.EndToEndTester.java kompiliert und mit java main.EndToEndTester 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 class EndToEndTester { public static void main(String[] args) { try { // Try to load the class named "CompilerInput" diff --git a/src/test/java/main/FailureTest.java b/src/test/java/main/FailureTest.java index 5a2e1c8..60c504b 100644 --- a/src/test/java/main/FailureTest.java +++ b/src/test/java/main/FailureTest.java @@ -3,71 +3,45 @@ package main; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; -import org.antlr.v4.runtime.CharStream; -import org.antlr.v4.runtime.CharStreams; import org.junit.jupiter.api.Test; import javax.tools.JavaCompiler; import javax.tools.ToolProvider; import java.io.File; -import java.io.IOException; -import java.nio.file.Paths; -import java.util.Arrays; -import java.util.List; public class FailureTest { - private static final List TEST_FILES = Arrays.asList( - "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" - ); - /** * This test method checks if invalid Java files fail to compile as expected. * It uses the JavaCompiler from the ToolProvider to compile the files. * The test passes if all the files fail to compile. */ @Test - public void invalidJavaFilesTest() { + public void areTestFilesActuallyFailTest() { // Get the system Java compiler - JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); - + JavaCompiler javac = ToolProvider.getSystemJavaCompiler(); // Assert that the compiler is available - assertNotNull(compiler, "Java Compiler is not available"); + assertNotNull(javac, "Java Compiler is not available"); - // Iterate over the test files - for (String fileName : TEST_FILES) { - // Create a File object for the current file - File file = new File(fileName); + String directoryPath = "src/test/resources/input/failureTests"; + File folder = new File(directoryPath); - // Try to compile the file and get the result - // The run method returns 0 if the compilation was successful, and non-zero otherwise - int result = compiler.run(null, null, null, file.getPath()); + if (folder.isDirectory()) { + File[] files = folder.listFiles((dir, name) -> name.endsWith(".java")); - // Assert that the compilation failed (i.e., the result is non-zero) - assertTrue(result != 0, "Expected compilation failure for " + fileName); - } - } + if (files != null) { + for (File file : files) { + // Try to compile the file and get the result + // The run method returns 0 if the compilation was successful, and non-zero otherwise + int result = javac.run(null, null, null, file.getPath()); - // schmeißt John Fehler, wenn namen doppelt sind? - // Input: ParseTree mit genanntem Fehler - // Output: Fehlermeldung - @Test - void typedASTTest() throws IOException { - CharStream codeCharStream = null; - try { - 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()); + // Assert that the compilation failed (i.e., the result is non-zero) + assertTrue(result != 0, "Expected compilation failure for " + file.getName()); + } + } else { + System.out.println("No files found in the directory."); + } + } else { + System.out.println("The provided path is not a directory."); } } } diff --git a/src/test/java/main/FeatureTest.java b/src/test/java/main/FeatureTest.java new file mode 100644 index 0000000..a3e30de --- /dev/null +++ b/src/test/java/main/FeatureTest.java @@ -0,0 +1,46 @@ +package main; + +import org.junit.jupiter.api.Test; + +import javax.tools.JavaCompiler; +import javax.tools.ToolProvider; +import java.io.File; + +import static org.junit.jupiter.api.Assertions.*; + +public class FeatureTest { + /** + * This test method checks if valid Java files compile successfully. + * It uses the JavaCompiler from the ToolProvider to compile the files. + * The test passes if all the files compile without errors. + */ + @Test + public void areTestFilesActuallyValid() { + // Get the system Java compiler + JavaCompiler javac = ToolProvider.getSystemJavaCompiler(); + // Assert that the compiler is available + assertNotNull(javac, "Java Compiler is not available"); + + String directoryPath = "src/test/resources/input/featureTests"; + File folder = new File(directoryPath); + + if (folder.isDirectory()) { + File[] files = folder.listFiles((dir, name) -> name.endsWith(".java")); + + if (files != null) { + for (File file : files) { + // Try to compile the file and get the result + // The run method returns 0 if the compilation was successful, and non-zero otherwise + int result = javac.run(null, null, null, file.getPath()); + + // Assert that the compilation succeeded (i.e., the result is zero) + assertEquals(0, result, "Expected compilation success for " + file.getName()); + } + } else { + System.out.println("No files found in the directory."); + } + } else { + System.out.println("The provided path is not a directory."); + } + } +} diff --git a/src/test/java/main/MainTest.java b/src/test/java/main/MainTest.java index 363fa35..24389bc 100644 --- a/src/test/java/main/MainTest.java +++ b/src/test/java/main/MainTest.java @@ -7,14 +7,14 @@ import org.antlr.v4.runtime.CharStreams; import java.io.IOException; import java.nio.file.Paths; -import static org.junit.jupiter.api.Assertions.assertEquals; /** - * run: mvn test + * run every test: mvn test + * Nutzen dieser Klasse: Eigentlich nicht vorhanden, in der Main gibts nichts zu testen */ public class MainTest { @Test - void testEmptyClass() { + void test() { CharStream codeCharStream = null; try { codeCharStream = CharStreams.fromPath(Paths.get("src/main/test/resources/CompilerInput.java")); diff --git a/src/test/java/parser/AstBuilderTest.java b/src/test/java/parser/AstBuilderTest.java new file mode 100644 index 0000000..b5bec24 --- /dev/null +++ b/src/test/java/parser/AstBuilderTest.java @@ -0,0 +1,103 @@ +package parser; + +import ast.ClassNode; +import ast.ProgramNode; +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 org.junit.jupiter.api.Test; +import parser.astBuilder.ASTBuilder; +import parser.generated.SimpleJavaLexer; +import parser.generated.SimpleJavaParser; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class AstBuilderTest { + + @Test + public void astBuilderTest() { + // ---------------- Leere Klasse nachgebaut ---------------- + + ProgramNode expectedASTEmptyClass = new ProgramNode(); + + // public class Name {} + ClassNode nameClass = new ClassNode("public", "Name"); + + expectedASTEmptyClass.addClass(nameClass); + + + // ---------------- Leere Klasse erzeugt ---------------- + + // 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 parseTreeEmptyClass = parser.program(); // parse the input + + /* AST builder -> AST */ + ASTBuilder astBuilder = new ASTBuilder(); + ProgramNode actualASTEmptyClass = (ProgramNode) new ASTBuilder().visit(parseTreeEmptyClass); + + + // ---------------- Vergleichen ---------------- + + String expectedASTasString = expectedASTEmptyClass.toString(); + String actualASTasString = new ASTBuilder().visit(parseTreeEmptyClass).toString(); + + // Wie vergleiche ich das? + assertEquals(expectedASTasString, actualASTasString); + assertEquals(expectedASTEmptyClass, actualASTEmptyClass); + } + + + + + + + + + + + + + + + // ---------------- Alter CompilerInput nachgebaut ---------------- + // ProgramNode startNode = new ProgramNode(); + // public class CompilerInput {} + // ClassNode compilerInputClass = new ClassNode(new AccessTypeNode(EnumAccessTypeNode.PUBLIC), "CompilerInput"); + // public int a; + // compilerInputClass.addMember(new FieldNode(new AccessTypeNode(EnumAccessTypeNode.PUBLIC), new BaseTypeNode(EnumTypeNode.INT), "a")); + // public static int testMethod(char x) { return 0; } + /* compilerInputClass.addMember( + new MethodNode( + new AccessTypeNode(EnumAccessTypeNode.PUBLIC), + new BaseTypeNode(EnumTypeNode.INT), + "testMethod", + new ParameterListNode(List.of(new ParameterNode(new BaseTypeNode(EnumTypeNode.CHAR), "x"))), + List.of(new ReturnStatementNode(new LiteralNode(0))) + )); + + ClassNode testClass = new ClassNode(new AccessTypeNode(EnumAccessTypeNode.PUBLIC), "Test"); + testClass.addMember( + new MethodNode( + new AccessTypeNode(EnumAccessTypeNode.PUBLIC), + new BaseTypeNode(EnumTypeNode.INT), + "testMethod", + new ParameterListNode(List.of(new ParameterNode(new BaseTypeNode(EnumTypeNode.CHAR), "x"), new ParameterNode(new BaseTypeNode(EnumTypeNode.INT), "a"))), + List.of(new ReturnStatementNode(new LiteralNode(0))) + ) + ); + + */ + + //compilerInputClass.addClass(testClass); + + // startNode.addClass(compilerInputClass); + // startNode.addClass(testClass); +} diff --git a/src/test/java/parser/ParserTest.java b/src/test/java/parser/ParserTest.java index c75346c..c567b4b 100644 --- a/src/test/java/parser/ParserTest.java +++ b/src/test/java/parser/ParserTest.java @@ -1,16 +1,9 @@ package parser; -import ast.ClassNode; -import ast.ProgramNode; -import ast.member.FieldNode; -import ast.member.MethodNode; -import ast.parameter.ParameterNode; -import ast.statement.ReturnStatementNode; 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.astBuilder.ASTBuilder; import parser.generated.SimpleJavaLexer; import parser.generated.SimpleJavaParser; @@ -19,41 +12,13 @@ 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 expectedTokens = Arrays.asList("public", "class", "Name", "{", "}", ""); - List expectedTokenTypes = Arrays.asList("AccessModifier", "Class", "Identifier", "OpenCurlyBracket", "ClosedCurlyBracket", "EOF"); - List actualTokens = tokenStream.getTokens(); - - // 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() { @@ -83,80 +48,6 @@ public class ParserTest { // assertEquals(expectedTreeStructure, actualTreeStructure); } - @Test - public void astBuilderTest() { - // TODO: Implement this test method - - // ---------------- Alter CompilerInput nachgebaut ---------------- - // ProgramNode startNode = new ProgramNode(); - // public class CompilerInput {} - // ClassNode compilerInputClass = new ClassNode(new AccessTypeNode(EnumAccessTypeNode.PUBLIC), "CompilerInput"); - // public int a; - // compilerInputClass.addMember(new FieldNode(new AccessTypeNode(EnumAccessTypeNode.PUBLIC), new BaseTypeNode(EnumTypeNode.INT), "a")); - // public static int testMethod(char x) { return 0; } - /* compilerInputClass.addMember( - new MethodNode( - new AccessTypeNode(EnumAccessTypeNode.PUBLIC), - new BaseTypeNode(EnumTypeNode.INT), - "testMethod", - new ParameterListNode(List.of(new ParameterNode(new BaseTypeNode(EnumTypeNode.CHAR), "x"))), - List.of(new ReturnStatementNode(new LiteralNode(0))) - )); - - ClassNode testClass = new ClassNode(new AccessTypeNode(EnumAccessTypeNode.PUBLIC), "Test"); - testClass.addMember( - new MethodNode( - new AccessTypeNode(EnumAccessTypeNode.PUBLIC), - new BaseTypeNode(EnumTypeNode.INT), - "testMethod", - new ParameterListNode(List.of(new ParameterNode(new BaseTypeNode(EnumTypeNode.CHAR), "x"), new ParameterNode(new BaseTypeNode(EnumTypeNode.INT), "a"))), - List.of(new ReturnStatementNode(new LiteralNode(0))) - ) - ); - - */ - - //compilerInputClass.addClass(testClass); - - // startNode.addClass(compilerInputClass); - // startNode.addClass(testClass); - - // ---------------- Leere Klasse nachgebaut ---------------- - - ProgramNode expectedASTEmptyClass = new ProgramNode(); - - // public class Name {} - ClassNode nameClass = new ClassNode("public", "Name"); - - expectedASTEmptyClass.addClass(nameClass); - - - // ---------------- Leere Klasse erzeugt ---------------- - - // 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 parseTreeEmptyClass = parser.program(); // parse the input - - /* AST builder -> AST */ - ASTBuilder astBuilder = new ASTBuilder(); - ProgramNode actualASTEmptyClass = (ProgramNode) new ASTBuilder().visit(parseTreeEmptyClass); - - - // ---------------- Vergleichen ---------------- - - String expectedASTasString = expectedASTEmptyClass.toString(); - String actualASTasString = new ASTBuilder().visit(parseTreeEmptyClass).toString(); - - // Wie vergleiche ich das? - assertEquals(expectedASTasString, actualASTasString); - assertEquals(expectedASTEmptyClass, actualASTEmptyClass); - } // Helpers Variante 2.1 diff --git a/src/test/java/parser/ScannerTest.java b/src/test/java/parser/ScannerTest.java new file mode 100644 index 0000000..ba31a81 --- /dev/null +++ b/src/test/java/parser/ScannerTest.java @@ -0,0 +1,45 @@ +package parser; + +import org.antlr.v4.runtime.CharStream; +import org.antlr.v4.runtime.CharStreams; +import org.antlr.v4.runtime.CommonTokenStream; +import org.antlr.v4.runtime.Token; +import org.junit.jupiter.api.Test; +import parser.generated.SimpleJavaLexer; + +import java.util.Arrays; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class ScannerTest { + + /** + * 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 expectedTokens = Arrays.asList("public", "class", "Name", "{", "}", ""); + List expectedTokenTypes = Arrays.asList("AccessModifier", "Class", "Identifier", "OpenCurlyBracket", "ClosedCurlyBracket", "EOF"); + List actualTokens = tokenStream.getTokens(); + + // 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())); + } + } +} From d594bacb7d6b5817d3f5b8b2ed73eb807f48c01c Mon Sep 17 00:00:00 2001 From: Lucas <89882946+notbad3500@users.noreply.github.com> Date: Wed, 26 Jun 2024 16:21:04 +0200 Subject: [PATCH 05/10] Semantic Tests refactored --- src/main/java/semantic/Scope.java | 2 +- src/main/java/semantic/SemanticAnalyzer.java | 2 +- .../AlreadyDeclearedException.java | 2 +- .../AlreadyDefinedException.java | 2 +- .../MultipleReturnTypes.java | 2 +- .../NotDeclearedException.java | 2 +- .../TypeMismatchException.java | 2 +- .../semantic/exceptions/UnknownException.java | 9 + src/test/java/semantic/EndToTAST.java | 282 ------------------ src/test/java/semantic/EndToTypedAstTest.java | 218 ++++++++++++++ src/test/java/semantic/SemanticTest.java | 13 - .../FieldAlreadyDecleared.java | 1 + .../MultipleReturnTypes.java} | 1 + .../NotDecleared.java | 1 + .../ParameterAlreadyDecleared.java | 1 + .../ReturnTypeMismatch.java} | 1 + .../TypeMismatchIntBool.java | 1 + .../TypeMismatchRefType.java | 1 + .../WrongIfClause.java | 1 + .../CorrectReturnType.java} | 0 .../typedAstFeaturesTests}/CorrectTest.java | 0 .../{semantic => trees}/correctRefType.json | 0 .../{semantic => trees}/refTypeMismatch.json | 0 .../resources/{semantic => trees}/test.json | 0 24 files changed, 242 insertions(+), 302 deletions(-) rename src/main/java/semantic/{exeptions => exceptions}/AlreadyDeclearedException.java (84%) rename src/main/java/semantic/{exeptions => exceptions}/AlreadyDefinedException.java (83%) rename src/main/java/semantic/{exeptions => exceptions}/MultipleReturnTypes.java (83%) rename src/main/java/semantic/{exeptions => exceptions}/NotDeclearedException.java (83%) rename src/main/java/semantic/{exeptions => exceptions}/TypeMismatchException.java (83%) create mode 100644 src/main/java/semantic/exceptions/UnknownException.java delete mode 100644 src/test/java/semantic/EndToTAST.java create mode 100644 src/test/java/semantic/EndToTypedAstTest.java rename src/test/resources/{semantic/endToTAST => input/typedAstExceptionsTests}/FieldAlreadyDecleared.java (73%) rename src/test/resources/{semantic/endToTAST/MultipleRetTypes.java => input/typedAstExceptionsTests/MultipleReturnTypes.java} (77%) rename src/test/resources/{semantic/endToTAST => input/typedAstExceptionsTests}/NotDecleared.java (73%) rename src/test/resources/{semantic/endToTAST => input/typedAstExceptionsTests}/ParameterAlreadyDecleared.java (66%) rename src/test/resources/{semantic/endToTAST/retTypeMismatch.java => input/typedAstExceptionsTests/ReturnTypeMismatch.java} (72%) rename src/test/resources/{semantic/endToTAST => input/typedAstExceptionsTests}/TypeMismatchIntBool.java (74%) rename src/test/resources/{semantic/endToTAST => input/typedAstExceptionsTests}/TypeMismatchRefType.java (85%) rename src/test/resources/{semantic/endToTAST => input/typedAstExceptionsTests}/WrongIfClause.java (67%) rename src/test/resources/{semantic/endToTAST/CorrectRetType.java => input/typedAstFeaturesTests/CorrectReturnType.java} (100%) rename src/test/resources/{semantic/endToTAST => input/typedAstFeaturesTests}/CorrectTest.java (100%) rename src/test/resources/{semantic => trees}/correctRefType.json (100%) rename src/test/resources/{semantic => trees}/refTypeMismatch.json (100%) rename src/test/resources/{semantic => trees}/test.json (100%) diff --git a/src/main/java/semantic/Scope.java b/src/main/java/semantic/Scope.java index 39dd2f8..06647ec 100644 --- a/src/main/java/semantic/Scope.java +++ b/src/main/java/semantic/Scope.java @@ -1,7 +1,7 @@ package semantic; import ast.type.type.*; -import semantic.exeptions.AlreadyDeclearedException; +import semantic.exceptions.AlreadyDeclearedException; import java.util.HashMap; import java.util.Stack; diff --git a/src/main/java/semantic/SemanticAnalyzer.java b/src/main/java/semantic/SemanticAnalyzer.java index c409c0d..f4461eb 100644 --- a/src/main/java/semantic/SemanticAnalyzer.java +++ b/src/main/java/semantic/SemanticAnalyzer.java @@ -25,7 +25,7 @@ import ast.statement.statementexpression.crementExpression.IncrementExpressionNo import ast.statement.statementexpression.methodcallstatementnexpression.MethodCallStatementExpressionNode; import ast.type.type.*; import semantic.context.Context; -import semantic.exeptions.*; +import semantic.exceptions.*; import typechecker.TypeCheckResult; public class SemanticAnalyzer implements SemanticVisitor { diff --git a/src/main/java/semantic/exeptions/AlreadyDeclearedException.java b/src/main/java/semantic/exceptions/AlreadyDeclearedException.java similarity index 84% rename from src/main/java/semantic/exeptions/AlreadyDeclearedException.java rename to src/main/java/semantic/exceptions/AlreadyDeclearedException.java index d00fd36..d7ffccc 100644 --- a/src/main/java/semantic/exeptions/AlreadyDeclearedException.java +++ b/src/main/java/semantic/exceptions/AlreadyDeclearedException.java @@ -1,4 +1,4 @@ -package semantic.exeptions; +package semantic.exceptions; public class AlreadyDeclearedException extends RuntimeException { diff --git a/src/main/java/semantic/exeptions/AlreadyDefinedException.java b/src/main/java/semantic/exceptions/AlreadyDefinedException.java similarity index 83% rename from src/main/java/semantic/exeptions/AlreadyDefinedException.java rename to src/main/java/semantic/exceptions/AlreadyDefinedException.java index 441a5d9..0128bda 100644 --- a/src/main/java/semantic/exeptions/AlreadyDefinedException.java +++ b/src/main/java/semantic/exceptions/AlreadyDefinedException.java @@ -1,4 +1,4 @@ -package semantic.exeptions; +package semantic.exceptions; public class AlreadyDefinedException extends RuntimeException { diff --git a/src/main/java/semantic/exeptions/MultipleReturnTypes.java b/src/main/java/semantic/exceptions/MultipleReturnTypes.java similarity index 83% rename from src/main/java/semantic/exeptions/MultipleReturnTypes.java rename to src/main/java/semantic/exceptions/MultipleReturnTypes.java index 59f92fa..3f74874 100644 --- a/src/main/java/semantic/exeptions/MultipleReturnTypes.java +++ b/src/main/java/semantic/exceptions/MultipleReturnTypes.java @@ -1,4 +1,4 @@ -package semantic.exeptions; +package semantic.exceptions; public class MultipleReturnTypes extends RuntimeException { diff --git a/src/main/java/semantic/exeptions/NotDeclearedException.java b/src/main/java/semantic/exceptions/NotDeclearedException.java similarity index 83% rename from src/main/java/semantic/exeptions/NotDeclearedException.java rename to src/main/java/semantic/exceptions/NotDeclearedException.java index aa223a0..af1924f 100644 --- a/src/main/java/semantic/exeptions/NotDeclearedException.java +++ b/src/main/java/semantic/exceptions/NotDeclearedException.java @@ -1,4 +1,4 @@ -package semantic.exeptions; +package semantic.exceptions; public class NotDeclearedException extends RuntimeException { diff --git a/src/main/java/semantic/exeptions/TypeMismatchException.java b/src/main/java/semantic/exceptions/TypeMismatchException.java similarity index 83% rename from src/main/java/semantic/exeptions/TypeMismatchException.java rename to src/main/java/semantic/exceptions/TypeMismatchException.java index 93fb62b..2a3fe07 100644 --- a/src/main/java/semantic/exeptions/TypeMismatchException.java +++ b/src/main/java/semantic/exceptions/TypeMismatchException.java @@ -1,4 +1,4 @@ -package semantic.exeptions; +package semantic.exceptions; public class TypeMismatchException extends RuntimeException { diff --git a/src/main/java/semantic/exceptions/UnknownException.java b/src/main/java/semantic/exceptions/UnknownException.java new file mode 100644 index 0000000..8869fdc --- /dev/null +++ b/src/main/java/semantic/exceptions/UnknownException.java @@ -0,0 +1,9 @@ +package semantic.exceptions; + +public class UnknownException extends RuntimeException { + + public UnknownException(String message) { + super(message); + } + +} diff --git a/src/test/java/semantic/EndToTAST.java b/src/test/java/semantic/EndToTAST.java deleted file mode 100644 index 3189802..0000000 --- a/src/test/java/semantic/EndToTAST.java +++ /dev/null @@ -1,282 +0,0 @@ -package semantic; - -import ast.ASTNode; -import ast.ProgramNode; -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 org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import parser.astBuilder.ASTBuilder; -import parser.generated.SimpleJavaLexer; -import parser.generated.SimpleJavaParser; -import semantic.exeptions.AlreadyDeclearedException; -import semantic.exeptions.MultipleReturnTypes; -import semantic.exeptions.NotDeclearedException; -import semantic.exeptions.TypeMismatchException; - -import java.io.IOException; -import java.nio.file.Paths; - -import static org.junit.jupiter.api.Assertions.*; - -public class EndToTAST { - - @BeforeEach - public void setup(){ - SemanticAnalyzer.clearAnalyzer(); - } - - @Test - public void CorrectTest(){ - - CharStream codeCharStream = null; - try { - codeCharStream = CharStreams.fromPath(Paths.get("src/test/resources/semantic/endToTAST/CorrectTest.java")); - } catch (IOException e) { - throw new RuntimeException(e); - } - SimpleJavaLexer lexer = new SimpleJavaLexer(codeCharStream); - CommonTokenStream tokenStream = new CommonTokenStream(lexer); - - SimpleJavaParser parser = new SimpleJavaParser(tokenStream); - ParseTree parseTree = parser.program(); // parse the input - - /* ------------------------- AST builder -> AST ------------------------- */ - ASTBuilder astBuilder = new ASTBuilder(); - ProgramNode abstractSyntaxTree = (ProgramNode) astBuilder.visit(parseTree); - - ASTNode tast = SemanticAnalyzer.generateTast(abstractSyntaxTree); - - - assertEquals(SemanticAnalyzer.errors.size(), 0); - assertNotNull(tast); - - } - - @Test - public void notDecleared() { - - CharStream codeCharStream = null; - try { - codeCharStream = CharStreams.fromPath(Paths.get("src/test/resources/semantic/endToTAST/NotDecleared.java")); - } catch (IOException e) { - throw new RuntimeException(e); - } - SimpleJavaLexer lexer = new SimpleJavaLexer(codeCharStream); - CommonTokenStream tokenStream = new CommonTokenStream(lexer); - - SimpleJavaParser parser = new SimpleJavaParser(tokenStream); - ParseTree parseTree = parser.program(); // parse the input - - /* ------------------------- AST builder -> AST ------------------------- */ - ASTBuilder astBuilder = new ASTBuilder(); - ProgramNode abstractSyntaxTree = (ProgramNode) astBuilder.visit(parseTree); - - ASTNode tast = SemanticAnalyzer.generateTast(abstractSyntaxTree); - - assertFalse(SemanticAnalyzer.errors.isEmpty()); - assertInstanceOf(NotDeclearedException.class, SemanticAnalyzer.errors.getFirst()); - - } - - @Test - public void typeMismatch(){ - - CharStream codeCharStream = null; - try { - codeCharStream = CharStreams.fromPath(Paths.get("src/test/resources/semantic/endToTAST/TypeMismatchIntBool.java")); - } catch (IOException e) { - throw new RuntimeException(e); - } - SimpleJavaLexer lexer = new SimpleJavaLexer(codeCharStream); - CommonTokenStream tokenStream = new CommonTokenStream(lexer); - - SimpleJavaParser parser = new SimpleJavaParser(tokenStream); - ParseTree parseTree = parser.program(); - - ASTBuilder astBuilder = new ASTBuilder(); - ProgramNode abstractSyntaxTree = (ProgramNode) astBuilder.visit(parseTree); - - ASTNode tast = SemanticAnalyzer.generateTast(abstractSyntaxTree); - - assertFalse(SemanticAnalyzer.errors.isEmpty()); - assertInstanceOf(TypeMismatchException.class, SemanticAnalyzer.errors.getFirst()); - - } - - @Test - public void parameterAlreadyDecleared(){ - - CharStream codeCharStream = null; - try { - codeCharStream = CharStreams.fromPath(Paths.get("src/test/resources/semantic/endToTAST/ParameterAlreadyDecleared.java")); - } catch (IOException e) { - throw new RuntimeException(e); - } - SimpleJavaLexer lexer = new SimpleJavaLexer(codeCharStream); - CommonTokenStream tokenStream = new CommonTokenStream(lexer); - - SimpleJavaParser parser = new SimpleJavaParser(tokenStream); - ParseTree parseTree = parser.program(); - - ASTBuilder astBuilder = new ASTBuilder(); - ProgramNode abstractSyntaxTree = (ProgramNode) astBuilder.visit(parseTree); - - ASTNode tast = SemanticAnalyzer.generateTast(abstractSyntaxTree); - - assertFalse(SemanticAnalyzer.errors.isEmpty()); - assertInstanceOf(AlreadyDeclearedException.class, SemanticAnalyzer.errors.getFirst()); - - } - - @Test - public void fieldAlreadyDecleared(){ - - CharStream codeCharStream = null; - try { - codeCharStream = CharStreams.fromPath(Paths.get("src/test/resources/semantic/endToTAST/FieldAlreadyDecleared.java")); - } catch (IOException e) { - throw new RuntimeException(e); - } - SimpleJavaLexer lexer = new SimpleJavaLexer(codeCharStream); - CommonTokenStream tokenStream = new CommonTokenStream(lexer); - - SimpleJavaParser parser = new SimpleJavaParser(tokenStream); - ParseTree parseTree = parser.program(); - - ASTBuilder astBuilder = new ASTBuilder(); - ProgramNode abstractSyntaxTree = (ProgramNode) astBuilder.visit(parseTree); - - ASTNode tast = SemanticAnalyzer.generateTast(abstractSyntaxTree); - - assertFalse(SemanticAnalyzer.errors.isEmpty()); - assertInstanceOf(AlreadyDeclearedException.class, SemanticAnalyzer.errors.getFirst()); - - } - - @Test - public void typeMismatchRefType(){ - - CharStream codeCharStream = null; - try { - codeCharStream = CharStreams.fromPath(Paths.get("src/test/resources/semantic/endToTAST/TypeMismatchRefType.java")); - } catch (IOException e) { - throw new RuntimeException(e); - } - SimpleJavaLexer lexer = new SimpleJavaLexer(codeCharStream); - CommonTokenStream tokenStream = new CommonTokenStream(lexer); - - SimpleJavaParser parser = new SimpleJavaParser(tokenStream); - ParseTree parseTree = parser.program(); - - ASTBuilder astBuilder = new ASTBuilder(); - ProgramNode abstractSyntaxTree = (ProgramNode) astBuilder.visit(parseTree); - - ASTNode tast = SemanticAnalyzer.generateTast(abstractSyntaxTree); - - assertFalse(SemanticAnalyzer.errors.isEmpty()); - assertInstanceOf(TypeMismatchException.class, SemanticAnalyzer.errors.getFirst()); - - } - - @Test - public void correctRetType(){ - - CharStream codeCharStream = null; - try { - codeCharStream = CharStreams.fromPath(Paths.get("src/test/resources/semantic/endToTAST/CorrectRetType.java")); - } catch (IOException e) { - throw new RuntimeException(e); - } - SimpleJavaLexer lexer = new SimpleJavaLexer(codeCharStream); - CommonTokenStream tokenStream = new CommonTokenStream(lexer); - - SimpleJavaParser parser = new SimpleJavaParser(tokenStream); - ParseTree parseTree = parser.program(); - - ASTBuilder astBuilder = new ASTBuilder(); - ProgramNode abstractSyntaxTree = (ProgramNode) astBuilder.visit(parseTree); - - ASTNode tast = SemanticAnalyzer.generateTast(abstractSyntaxTree); - - assertTrue(SemanticAnalyzer.errors.isEmpty()); - - } - - @Test - public void retTypeMismatch(){ - - CharStream codeCharStream = null; - try { - codeCharStream = CharStreams.fromPath(Paths.get("src/test/resources/semantic/endToTAST/retTypeMismatch.java")); - } catch (IOException e) { - throw new RuntimeException(e); - } - SimpleJavaLexer lexer = new SimpleJavaLexer(codeCharStream); - CommonTokenStream tokenStream = new CommonTokenStream(lexer); - - SimpleJavaParser parser = new SimpleJavaParser(tokenStream); - ParseTree parseTree = parser.program(); - - ASTBuilder astBuilder = new ASTBuilder(); - ProgramNode abstractSyntaxTree = (ProgramNode) astBuilder.visit(parseTree); - - ASTNode tast = SemanticAnalyzer.generateTast(abstractSyntaxTree); - - assertFalse(SemanticAnalyzer.errors.isEmpty()); - assertInstanceOf(TypeMismatchException.class, SemanticAnalyzer.errors.getFirst()); - - } - - @Test - public void multipleRetType(){ - - CharStream codeCharStream = null; - try { - codeCharStream = CharStreams.fromPath(Paths.get("src/test/resources/semantic/endToTAST/MultipleRetTypes.java")); - } catch (IOException e) { - throw new RuntimeException(e); - } - SimpleJavaLexer lexer = new SimpleJavaLexer(codeCharStream); - CommonTokenStream tokenStream = new CommonTokenStream(lexer); - - SimpleJavaParser parser = new SimpleJavaParser(tokenStream); - ParseTree parseTree = parser.program(); - - ASTBuilder astBuilder = new ASTBuilder(); - ProgramNode abstractSyntaxTree = (ProgramNode) astBuilder.visit(parseTree); - - ASTNode tast = SemanticAnalyzer.generateTast(abstractSyntaxTree); - - assertFalse(SemanticAnalyzer.errors.isEmpty()); - assertInstanceOf(MultipleReturnTypes.class, SemanticAnalyzer.errors.getFirst()); - - } - - @Test - public void wrongTypeInIfClause(){ - - CharStream codeCharStream = null; - try { - codeCharStream = CharStreams.fromPath(Paths.get("src/test/resources/semantic/endToTAST/WrongIfClause.java")); - } catch (IOException e) { - throw new RuntimeException(e); - } - SimpleJavaLexer lexer = new SimpleJavaLexer(codeCharStream); - CommonTokenStream tokenStream = new CommonTokenStream(lexer); - - SimpleJavaParser parser = new SimpleJavaParser(tokenStream); - ParseTree parseTree = parser.program(); - - ASTBuilder astBuilder = new ASTBuilder(); - ProgramNode abstractSyntaxTree = (ProgramNode) astBuilder.visit(parseTree); - - ASTNode tast = SemanticAnalyzer.generateTast(abstractSyntaxTree); - - assertFalse(SemanticAnalyzer.errors.isEmpty()); - - } - -} diff --git a/src/test/java/semantic/EndToTypedAstTest.java b/src/test/java/semantic/EndToTypedAstTest.java new file mode 100644 index 0000000..9bf5485 --- /dev/null +++ b/src/test/java/semantic/EndToTypedAstTest.java @@ -0,0 +1,218 @@ +package semantic; + +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 ast.ASTNode; +import ast.ProgramNode; + +import parser.astBuilder.ASTBuilder; +import parser.generated.SimpleJavaLexer; +import parser.generated.SimpleJavaParser; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.net.URL; +import java.net.URLClassLoader; +import java.nio.file.Paths; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; + +public class EndToTypedAstTest { + private static final Map> exceptionMap = new HashMap<>(); + + @Test + public void exceptionsTest() { + String directoryPath = "src/test/resources/input/typedAstExceptionsTests"; + File folder = new File(directoryPath); + + try { + loadCustomExceptions(); + System.out.println("Custom exceptions loaded successfully."); + } catch (Exception e) { + throw new RuntimeException("Failed to load custom exceptions", e); + + } + + if (folder.isDirectory()) { + File[] files = folder.listFiles((_, name) -> name.endsWith(".java")); + if (files != null) { + for (File file : files) { + String expectedException = extractExpectedException(file); + + SemanticAnalyzer.clearAnalyzer(); + CharStream codeCharStream; + try { + codeCharStream = CharStreams.fromPath(Paths.get(file.getPath())); + } catch (IOException e) { + throw new RuntimeException(e); + } + + SimpleJavaLexer lexer = new SimpleJavaLexer(codeCharStream); + CommonTokenStream tokenStream = new CommonTokenStream(lexer); + + SimpleJavaParser parser = new SimpleJavaParser(tokenStream); + ParseTree parseTree = parser.program(); + + ASTBuilder astBuilder = new ASTBuilder(); + ProgramNode abstractSyntaxTree = (ProgramNode) astBuilder.visit(parseTree); + + ASTNode typedAst = SemanticAnalyzer.generateTast(abstractSyntaxTree); + + if (expectedException != null) { + System.out.println("Testing the file: " + file.getName()); + assertFalse(SemanticAnalyzer.errors.isEmpty(), "Expected an exception, but none was found."); + assertInstanceOf(getExceptionClass(expectedException), SemanticAnalyzer.errors.getFirst()); + } else { + System.out.println("No expected exception specified."); + // If no expected exception is specified, you might want to add a different check + // e.g., assertTrue(SemanticAnalyzer.errors.isEmpty(), "No exceptions expected, but some were found."); + } + } + } else { + System.out.println("No files found in the directory."); + } + } else { + System.out.println("The provided path is not a directory."); + } + } + + @Test + public void featureTest(){ + String directoryPath = "src/test/resources/input/typedAstFeaturesTests"; + File folder = new File(directoryPath); + if (folder.isDirectory()) { + File[] files = folder.listFiles((_, name) -> name.endsWith(".java")); + if (files != null) { + for (File file : files) { + SemanticAnalyzer.clearAnalyzer(); + CharStream codeCharStream; + try { + codeCharStream = CharStreams.fromPath(Paths.get(file.getPath())); + } catch (IOException e) { + throw new RuntimeException(e); + } + + SimpleJavaLexer lexer = new SimpleJavaLexer(codeCharStream); + CommonTokenStream tokenStream = new CommonTokenStream(lexer); + + SimpleJavaParser parser = new SimpleJavaParser(tokenStream); + ParseTree parseTree = parser.program(); + + ASTBuilder astBuilder = new ASTBuilder(); + ProgramNode abstractSyntaxTree = (ProgramNode) astBuilder.visit(parseTree); + + ASTNode typedAst = SemanticAnalyzer.generateTast(abstractSyntaxTree); + + System.out.println("Testing the file: " + file.getName()); + assertTrue(SemanticAnalyzer.errors.isEmpty()); + assertNotNull(typedAst); + } + } else { + System.out.println("No files found in the directory."); + } + } else { + System.out.println("The provided path is not a directory."); + } + } + + + + + // ------------------ Helpers ------------------ + /** + * This method is used to extract the expected exception from a given file. + * It reads the file line by line and uses a regular expression to match the expected exception annotation. + * The expected exception annotation should be in the format: "// @expected: ExceptionName". + * If the expected exception annotation is found, it returns the name of the expected exception. + * If the expected exception annotation is not found, it returns null. + * + * @param file The file from which the expected exception is to be extracted. + * @return The name of the expected exception, or null if the expected exception annotation is not found. + */ + private String extractExpectedException(File file) { + String annotationPattern = "//\\s*@expected:\\s*(\\S+)"; + Pattern pattern = Pattern.compile(annotationPattern); + try (BufferedReader reader = new BufferedReader(new FileReader(file))) { + String line; + while ((line = reader.readLine()) != null) { + Matcher matcher = pattern.matcher(line); + if (matcher.find()) { + return matcher.group(1); + } + } + } catch (IOException e) { + e.printStackTrace(); + } + return null; + } + + /** + * This method is used to retrieve the Class object associated with a given exception name. + * It first prints the original exception name, then appends the package name to the exception name and prints it. + * It then retrieves the Class object from the exceptionMap using the fully qualified exception name. + * If the Class object is not found in the exceptionMap, it throws a RuntimeException. + * + * @param exceptionName The name of the exception for which the Class object is to be retrieved. + * @return The Class object associated with the given exception name. + * @throws RuntimeException If the Class object for the given exception name is not found in the exceptionMap. + */ +private Class getExceptionClass(String exceptionName) { + System.out.println(exceptionName); + exceptionName = "semantic.exceptions." + exceptionName; + System.out.println(exceptionName); + Class exceptionClass = exceptionMap.get(exceptionName); + if (exceptionClass == null) { + throw new RuntimeException("Exception class not found: " + exceptionName); + } + return exceptionClass; +} + + /** + * This method is used to load custom exceptions from a specified package. + * It first constructs the directory path from the package name and checks if the directory exists. + * If the directory does not exist, it throws an IllegalArgumentException. + * It then creates a URLClassLoader to load the classes from the directory. + * It iterates over all the files in the directory, and for each file, it constructs the class name and loads the class. + * If the loaded class is a subtype of Throwable, it adds the class to the exceptionMap. + * + * @throws Exception If any error occurs during class loading. + */ + private static void loadCustomExceptions() throws Exception { + final String packName = "semantic.exceptions"; + final String dirForMyClasses = "src/main/java/%s".formatted(packName.replace(".", "/")); + File folder = new File(dirForMyClasses); + if (!folder.isDirectory()) { + throw new IllegalArgumentException("The provided path is not a directory."); + } + + URL[] urls = {folder.toURI().toURL()}; + URLClassLoader classLoader; + try { + classLoader = new URLClassLoader(urls); + } catch (Exception e) { + throw new RuntimeException("Failed to create class loader", e); + } + + for (File file : Objects.requireNonNull(folder.listFiles())) { + String className = packName + "." + file.getName().replaceAll("\\.(?:class|java)$", ""); + System.out.printf("Loading custom exception: %s (=> %s)", file.getName(), className); + Class cls = classLoader.loadClass(className); + + if (Throwable.class.isAssignableFrom(cls)) { // Check if the class is a subtype of Throwable + exceptionMap.put(className, cls); + System.out.println("Loaded custom exception: " + className); + } + } + } +} \ No newline at end of file diff --git a/src/test/java/semantic/SemanticTest.java b/src/test/java/semantic/SemanticTest.java index 04fda3d..7680e8a 100644 --- a/src/test/java/semantic/SemanticTest.java +++ b/src/test/java/semantic/SemanticTest.java @@ -1,18 +1,5 @@ package semantic; -import ast.*; -import ast.member.FieldNode; -import ast.member.MemberNode; -import ast.member.MethodNode; -import ast.parameter.ParameterNode; - -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.*; - public class SemanticTest { diff --git a/src/test/resources/semantic/endToTAST/FieldAlreadyDecleared.java b/src/test/resources/input/typedAstExceptionsTests/FieldAlreadyDecleared.java similarity index 73% rename from src/test/resources/semantic/endToTAST/FieldAlreadyDecleared.java rename to src/test/resources/input/typedAstExceptionsTests/FieldAlreadyDecleared.java index 535a592..3a1ff04 100644 --- a/src/test/resources/semantic/endToTAST/FieldAlreadyDecleared.java +++ b/src/test/resources/input/typedAstExceptionsTests/FieldAlreadyDecleared.java @@ -1,3 +1,4 @@ +// @expected: AlreadyDeclearedException public class Example { public int a; diff --git a/src/test/resources/semantic/endToTAST/MultipleRetTypes.java b/src/test/resources/input/typedAstExceptionsTests/MultipleReturnTypes.java similarity index 77% rename from src/test/resources/semantic/endToTAST/MultipleRetTypes.java rename to src/test/resources/input/typedAstExceptionsTests/MultipleReturnTypes.java index a5680ed..f368e60 100644 --- a/src/test/resources/semantic/endToTAST/MultipleRetTypes.java +++ b/src/test/resources/input/typedAstExceptionsTests/MultipleReturnTypes.java @@ -1,3 +1,4 @@ +// @expected: MultipleReturnTypes public class Example { public static int testMethod(int x, char c){ diff --git a/src/test/resources/semantic/endToTAST/NotDecleared.java b/src/test/resources/input/typedAstExceptionsTests/NotDecleared.java similarity index 73% rename from src/test/resources/semantic/endToTAST/NotDecleared.java rename to src/test/resources/input/typedAstExceptionsTests/NotDecleared.java index 4aba5f8..acafa5b 100644 --- a/src/test/resources/semantic/endToTAST/NotDecleared.java +++ b/src/test/resources/input/typedAstExceptionsTests/NotDecleared.java @@ -1,3 +1,4 @@ +// @expected: NotDeclearedException public class Test { public static int testMethod(int x){ int a = b; diff --git a/src/test/resources/semantic/endToTAST/ParameterAlreadyDecleared.java b/src/test/resources/input/typedAstExceptionsTests/ParameterAlreadyDecleared.java similarity index 66% rename from src/test/resources/semantic/endToTAST/ParameterAlreadyDecleared.java rename to src/test/resources/input/typedAstExceptionsTests/ParameterAlreadyDecleared.java index d2b3425..7de53e0 100644 --- a/src/test/resources/semantic/endToTAST/ParameterAlreadyDecleared.java +++ b/src/test/resources/input/typedAstExceptionsTests/ParameterAlreadyDecleared.java @@ -1,3 +1,4 @@ +// @expected: AlreadyDeclearedException public class Example { public static int testMethod(char a, int a){ diff --git a/src/test/resources/semantic/endToTAST/retTypeMismatch.java b/src/test/resources/input/typedAstExceptionsTests/ReturnTypeMismatch.java similarity index 72% rename from src/test/resources/semantic/endToTAST/retTypeMismatch.java rename to src/test/resources/input/typedAstExceptionsTests/ReturnTypeMismatch.java index d3a2674..6a7f3cc 100644 --- a/src/test/resources/semantic/endToTAST/retTypeMismatch.java +++ b/src/test/resources/input/typedAstExceptionsTests/ReturnTypeMismatch.java @@ -1,3 +1,4 @@ +// @expected: TypeMismatchException public class Example { public static int testMethod(char x){ diff --git a/src/test/resources/semantic/endToTAST/TypeMismatchIntBool.java b/src/test/resources/input/typedAstExceptionsTests/TypeMismatchIntBool.java similarity index 74% rename from src/test/resources/semantic/endToTAST/TypeMismatchIntBool.java rename to src/test/resources/input/typedAstExceptionsTests/TypeMismatchIntBool.java index 9b609b6..ec304a2 100644 --- a/src/test/resources/semantic/endToTAST/TypeMismatchIntBool.java +++ b/src/test/resources/input/typedAstExceptionsTests/TypeMismatchIntBool.java @@ -1,3 +1,4 @@ +// @expected: TypeMismatchException public class Test { public boolean b; diff --git a/src/test/resources/semantic/endToTAST/TypeMismatchRefType.java b/src/test/resources/input/typedAstExceptionsTests/TypeMismatchRefType.java similarity index 85% rename from src/test/resources/semantic/endToTAST/TypeMismatchRefType.java rename to src/test/resources/input/typedAstExceptionsTests/TypeMismatchRefType.java index a7b8cc9..870b222 100644 --- a/src/test/resources/semantic/endToTAST/TypeMismatchRefType.java +++ b/src/test/resources/input/typedAstExceptionsTests/TypeMismatchRefType.java @@ -1,3 +1,4 @@ +// @expected: TypeMismatchException public class Test { public static int testMethod(ExampleA exampleA, ExampleB exampleB){ diff --git a/src/test/resources/semantic/endToTAST/WrongIfClause.java b/src/test/resources/input/typedAstExceptionsTests/WrongIfClause.java similarity index 67% rename from src/test/resources/semantic/endToTAST/WrongIfClause.java rename to src/test/resources/input/typedAstExceptionsTests/WrongIfClause.java index f73f052..e1b7c27 100644 --- a/src/test/resources/semantic/endToTAST/WrongIfClause.java +++ b/src/test/resources/input/typedAstExceptionsTests/WrongIfClause.java @@ -1,3 +1,4 @@ +// @expected: TypeMismatchException public class Example { public static void testMethod(int x){ diff --git a/src/test/resources/semantic/endToTAST/CorrectRetType.java b/src/test/resources/input/typedAstFeaturesTests/CorrectReturnType.java similarity index 100% rename from src/test/resources/semantic/endToTAST/CorrectRetType.java rename to src/test/resources/input/typedAstFeaturesTests/CorrectReturnType.java diff --git a/src/test/resources/semantic/endToTAST/CorrectTest.java b/src/test/resources/input/typedAstFeaturesTests/CorrectTest.java similarity index 100% rename from src/test/resources/semantic/endToTAST/CorrectTest.java rename to src/test/resources/input/typedAstFeaturesTests/CorrectTest.java diff --git a/src/test/resources/semantic/correctRefType.json b/src/test/resources/trees/correctRefType.json similarity index 100% rename from src/test/resources/semantic/correctRefType.json rename to src/test/resources/trees/correctRefType.json diff --git a/src/test/resources/semantic/refTypeMismatch.json b/src/test/resources/trees/refTypeMismatch.json similarity index 100% rename from src/test/resources/semantic/refTypeMismatch.json rename to src/test/resources/trees/refTypeMismatch.json diff --git a/src/test/resources/semantic/test.json b/src/test/resources/trees/test.json similarity index 100% rename from src/test/resources/semantic/test.json rename to src/test/resources/trees/test.json From 347bdcbd948de04d07eb1c82e6ae5d09acc8f3e4 Mon Sep 17 00:00:00 2001 From: Lucas <89882946+notbad3500@users.noreply.github.com> Date: Wed, 26 Jun 2024 16:22:38 +0200 Subject: [PATCH 06/10] Update .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 8c5079b..cb648af 100644 --- a/.gitignore +++ b/.gitignore @@ -83,3 +83,4 @@ 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 +.idea/inspectionProfiles/Project_Default.xml From 4e56760dd6c516b0d2b7162f97b9532242a44b6f Mon Sep 17 00:00:00 2001 From: Lucas <89882946+notbad3500@users.noreply.github.com> Date: Wed, 26 Jun 2024 16:28:53 +0200 Subject: [PATCH 07/10] Old spelling mistake in semantic fixed --- src/main/java/semantic/Scope.java | 4 ++-- src/main/java/semantic/SemanticAnalyzer.java | 10 +++++----- .../semantic/exceptions/AlreadyDeclaredException.java | 9 +++++++++ .../semantic/exceptions/AlreadyDeclearedException.java | 9 --------- .../java/semantic/exceptions/NotDeclaredException.java | 9 +++++++++ .../semantic/exceptions/NotDeclearedException.java | 9 --------- src/test/java/semantic/SemanticTest.java | 2 +- ...AlreadyDecleared.java => FieldAlreadyDeclared.java} | 2 +- .../{NotDecleared.java => NotDeclared.java} | 2 +- ...adyDecleared.java => ParameterAlreadyDeclared.java} | 2 +- 10 files changed, 29 insertions(+), 29 deletions(-) create mode 100644 src/main/java/semantic/exceptions/AlreadyDeclaredException.java delete mode 100644 src/main/java/semantic/exceptions/AlreadyDeclearedException.java create mode 100644 src/main/java/semantic/exceptions/NotDeclaredException.java delete mode 100644 src/main/java/semantic/exceptions/NotDeclearedException.java rename src/test/resources/input/typedAstExceptionsTests/{FieldAlreadyDecleared.java => FieldAlreadyDeclared.java} (73%) rename src/test/resources/input/typedAstExceptionsTests/{NotDecleared.java => NotDeclared.java} (73%) rename src/test/resources/input/typedAstExceptionsTests/{ParameterAlreadyDecleared.java => ParameterAlreadyDeclared.java} (66%) diff --git a/src/main/java/semantic/Scope.java b/src/main/java/semantic/Scope.java index 06647ec..b6b40c4 100644 --- a/src/main/java/semantic/Scope.java +++ b/src/main/java/semantic/Scope.java @@ -1,7 +1,7 @@ package semantic; import ast.type.type.*; -import semantic.exceptions.AlreadyDeclearedException; +import semantic.exceptions.AlreadyDeclaredException; import java.util.HashMap; import java.util.Stack; @@ -16,7 +16,7 @@ public class Scope { public void addLocalVar(String name, ITypeNode type) { if (this.contains(name)) { - throw new AlreadyDeclearedException("Variable " + name + " already exists in this scope"); + throw new AlreadyDeclaredException("Variable " + name + " already exists in this scope"); } localVars.peek().put(name, type); } diff --git a/src/main/java/semantic/SemanticAnalyzer.java b/src/main/java/semantic/SemanticAnalyzer.java index f4461eb..958a444 100644 --- a/src/main/java/semantic/SemanticAnalyzer.java +++ b/src/main/java/semantic/SemanticAnalyzer.java @@ -117,7 +117,7 @@ public class SemanticAnalyzer implements SemanticVisitor { if (Objects.equals(otherMethod, methodNode)) break; if (otherMethod.isSame(methodNode)) { - errors.add(new AlreadyDeclearedException( + errors.add(new AlreadyDeclaredException( "Method " + methodNode.getIdentifier() + " is already defined in class " + currentClass.identifier)); valid = false; @@ -130,8 +130,8 @@ public class SemanticAnalyzer implements SemanticVisitor { valid = valid && result.isValid(); try { currentScope.addLocalVar(parameter.identifier, parameter.type); - } catch (AlreadyDeclearedException e) { - errors.add(new AlreadyDeclearedException(parameter.identifier)); + } catch (AlreadyDeclaredException e) { + errors.add(new AlreadyDeclaredException(parameter.identifier)); } } @@ -165,7 +165,7 @@ public class SemanticAnalyzer implements SemanticVisitor { @Override public TypeCheckResult analyze(FieldNode toCheck) { if (currentFields.get(toCheck.identifier) != null) { - errors.add(new AlreadyDeclearedException("Already declared " + toCheck.identifier)); + errors.add(new AlreadyDeclaredException("Already declared " + toCheck.identifier)); return new TypeCheckResult(false, null); } else { currentFields.put(toCheck.identifier, toCheck.type); @@ -362,7 +362,7 @@ public class SemanticAnalyzer implements SemanticVisitor { } else if(currentFields.get(unary.identifier) != null) { return new TypeCheckResult(valid, currentFields.get(unary.identifier)); } else { - errors.add(new NotDeclearedException("Var is not Decleared")); + errors.add(new NotDeclaredException("Var is not Declared")); } return new TypeCheckResult(valid, null); } diff --git a/src/main/java/semantic/exceptions/AlreadyDeclaredException.java b/src/main/java/semantic/exceptions/AlreadyDeclaredException.java new file mode 100644 index 0000000..c59e104 --- /dev/null +++ b/src/main/java/semantic/exceptions/AlreadyDeclaredException.java @@ -0,0 +1,9 @@ +package semantic.exceptions; + +public class AlreadyDeclaredException extends RuntimeException { + + public AlreadyDeclaredException(String message) { + super(message); + } + +} diff --git a/src/main/java/semantic/exceptions/AlreadyDeclearedException.java b/src/main/java/semantic/exceptions/AlreadyDeclearedException.java deleted file mode 100644 index d7ffccc..0000000 --- a/src/main/java/semantic/exceptions/AlreadyDeclearedException.java +++ /dev/null @@ -1,9 +0,0 @@ -package semantic.exceptions; - -public class AlreadyDeclearedException extends RuntimeException { - - public AlreadyDeclearedException(String message) { - super(message); - } - -} diff --git a/src/main/java/semantic/exceptions/NotDeclaredException.java b/src/main/java/semantic/exceptions/NotDeclaredException.java new file mode 100644 index 0000000..307a55d --- /dev/null +++ b/src/main/java/semantic/exceptions/NotDeclaredException.java @@ -0,0 +1,9 @@ +package semantic.exceptions; + +public class NotDeclaredException extends RuntimeException { + + public NotDeclaredException(String message) { + super(message); + } + +} diff --git a/src/main/java/semantic/exceptions/NotDeclearedException.java b/src/main/java/semantic/exceptions/NotDeclearedException.java deleted file mode 100644 index af1924f..0000000 --- a/src/main/java/semantic/exceptions/NotDeclearedException.java +++ /dev/null @@ -1,9 +0,0 @@ -package semantic.exceptions; - -public class NotDeclearedException extends RuntimeException { - - public NotDeclearedException(String message) { - super(message); - } - -} diff --git a/src/test/java/semantic/SemanticTest.java b/src/test/java/semantic/SemanticTest.java index 7680e8a..a4039ac 100644 --- a/src/test/java/semantic/SemanticTest.java +++ b/src/test/java/semantic/SemanticTest.java @@ -22,7 +22,7 @@ public class SemanticTest { // ASTNode typedAst = SemanticAnalyzer.generateTast(programNode); // // assertEquals(1, SemanticAnalyzer.errors.size()); -// assertInstanceOf(AlreadyDeclearedException.class, SemanticAnalyzer.errors.getFirst()); +// assertInstanceOf(AlreadyDeclaredException.class, SemanticAnalyzer.errors.getFirst()); // assertNull(typedAst); // } // diff --git a/src/test/resources/input/typedAstExceptionsTests/FieldAlreadyDecleared.java b/src/test/resources/input/typedAstExceptionsTests/FieldAlreadyDeclared.java similarity index 73% rename from src/test/resources/input/typedAstExceptionsTests/FieldAlreadyDecleared.java rename to src/test/resources/input/typedAstExceptionsTests/FieldAlreadyDeclared.java index 3a1ff04..9b268e4 100644 --- a/src/test/resources/input/typedAstExceptionsTests/FieldAlreadyDecleared.java +++ b/src/test/resources/input/typedAstExceptionsTests/FieldAlreadyDeclared.java @@ -1,4 +1,4 @@ -// @expected: AlreadyDeclearedException +// @expected: AlreadyDeclaredException public class Example { public int a; diff --git a/src/test/resources/input/typedAstExceptionsTests/NotDecleared.java b/src/test/resources/input/typedAstExceptionsTests/NotDeclared.java similarity index 73% rename from src/test/resources/input/typedAstExceptionsTests/NotDecleared.java rename to src/test/resources/input/typedAstExceptionsTests/NotDeclared.java index acafa5b..948fe91 100644 --- a/src/test/resources/input/typedAstExceptionsTests/NotDecleared.java +++ b/src/test/resources/input/typedAstExceptionsTests/NotDeclared.java @@ -1,4 +1,4 @@ -// @expected: NotDeclearedException +// @expected: NotDeclaredException public class Test { public static int testMethod(int x){ int a = b; diff --git a/src/test/resources/input/typedAstExceptionsTests/ParameterAlreadyDecleared.java b/src/test/resources/input/typedAstExceptionsTests/ParameterAlreadyDeclared.java similarity index 66% rename from src/test/resources/input/typedAstExceptionsTests/ParameterAlreadyDecleared.java rename to src/test/resources/input/typedAstExceptionsTests/ParameterAlreadyDeclared.java index 7de53e0..25854c1 100644 --- a/src/test/resources/input/typedAstExceptionsTests/ParameterAlreadyDecleared.java +++ b/src/test/resources/input/typedAstExceptionsTests/ParameterAlreadyDeclared.java @@ -1,4 +1,4 @@ -// @expected: AlreadyDeclearedException +// @expected: AlreadyDeclaredException public class Example { public static int testMethod(char a, int a){ From 88a25207e981a9c00be7486bc26f04f298bf4a3d Mon Sep 17 00:00:00 2001 From: Maximilian Stahl Date: Wed, 26 Jun 2024 17:34:40 +0200 Subject: [PATCH 08/10] Added Interface and fixed bugs --- src/main/java/ast/statements/BlockNode.java | 6 +--- src/main/java/ast/statements/ElseNode.java | 8 ++++- src/main/java/ast/statements/IfElseNode.java | 8 ++++- src/main/java/ast/statements/IfNode.java | 9 ++++- .../java/ast/statements/StatementNode.java | 2 -- src/main/java/ast/statements/WhileNode.java | 14 +++++++- .../java/parser/astBuilder/ASTBuilder.java | 35 ++++++++++++------- src/main/resources/input/CompilerInput.java | 24 ++++++------- 8 files changed, 69 insertions(+), 37 deletions(-) delete mode 100644 src/main/java/ast/statements/StatementNode.java diff --git a/src/main/java/ast/statements/BlockNode.java b/src/main/java/ast/statements/BlockNode.java index ca14404..7a5a2ea 100644 --- a/src/main/java/ast/statements/BlockNode.java +++ b/src/main/java/ast/statements/BlockNode.java @@ -8,17 +8,13 @@ import visitor.Visitable; import java.util.ArrayList; import java.util.List; -public class BlockNode implements ASTNode, Visitable { +public class BlockNode implements IStatementNode, Visitable { public List statements = new ArrayList<>(); - public Boolean hasReturnStatement = false; public BlockNode() {} public void addStatement(IStatementNode statement) { statements.add(statement); - if(statement instanceof ReturnNode) { - hasReturnStatement = true; - } } @Override diff --git a/src/main/java/ast/statements/ElseNode.java b/src/main/java/ast/statements/ElseNode.java index 5b498cf..78b62f1 100644 --- a/src/main/java/ast/statements/ElseNode.java +++ b/src/main/java/ast/statements/ElseNode.java @@ -1,8 +1,10 @@ package ast.statements; import ast.ASTNode; +import semantic.SemanticVisitor; +import typechecker.TypeCheckResult; -public class ElseNode implements ASTNode { +public class ElseNode implements IStatementNode { BlockNode block; public ElseNode(BlockNode block) { @@ -10,4 +12,8 @@ public class ElseNode implements ASTNode { } + @Override + public TypeCheckResult accept(SemanticVisitor visitor) { + return null; + } } diff --git a/src/main/java/ast/statements/IfElseNode.java b/src/main/java/ast/statements/IfElseNode.java index 9d25390..34d40f3 100644 --- a/src/main/java/ast/statements/IfElseNode.java +++ b/src/main/java/ast/statements/IfElseNode.java @@ -1,11 +1,13 @@ package ast.statements; import ast.ASTNode; +import semantic.SemanticVisitor; +import typechecker.TypeCheckResult; import java.util.ArrayList; import java.util.List; -public class IfElseNode implements ASTNode { +public class IfElseNode implements IStatementNode { IfNode ifStatement; List elseIfStatements = new ArrayList<>(); ElseNode elseStatement; @@ -19,4 +21,8 @@ public class IfElseNode implements ASTNode { elseIfStatements.add(elseIfStament); } + @Override + public TypeCheckResult accept(SemanticVisitor visitor) { + return null; + } } diff --git a/src/main/java/ast/statements/IfNode.java b/src/main/java/ast/statements/IfNode.java index 3292a10..2f30788 100644 --- a/src/main/java/ast/statements/IfNode.java +++ b/src/main/java/ast/statements/IfNode.java @@ -2,8 +2,10 @@ package ast.statements; import ast.ASTNode; import ast.expressions.IExpressionNode; +import semantic.SemanticVisitor; +import typechecker.TypeCheckResult; -public class IfNode implements ASTNode { +public class IfNode implements IStatementNode { IExpressionNode expression; BlockNode block; @@ -11,4 +13,9 @@ public class IfNode implements ASTNode { this.expression = expression; this.block = block; } + + @Override + public TypeCheckResult accept(SemanticVisitor visitor) { + return null; + } } diff --git a/src/main/java/ast/statements/StatementNode.java b/src/main/java/ast/statements/StatementNode.java deleted file mode 100644 index 24985c1..0000000 --- a/src/main/java/ast/statements/StatementNode.java +++ /dev/null @@ -1,2 +0,0 @@ -package ast.statements;public class StatementNode { -} diff --git a/src/main/java/ast/statements/WhileNode.java b/src/main/java/ast/statements/WhileNode.java index fe9bfd2..01c1160 100644 --- a/src/main/java/ast/statements/WhileNode.java +++ b/src/main/java/ast/statements/WhileNode.java @@ -2,8 +2,10 @@ package ast.statements; import ast.ASTNode; import ast.expressions.IExpressionNode; +import semantic.SemanticVisitor; +import typechecker.TypeCheckResult; -public class WhileNode extends StatementNode implements ASTNode { +public class WhileNode implements IStatementNode { IExpressionNode expression; BlockNode block; @@ -11,4 +13,14 @@ public class WhileNode extends StatementNode implements ASTNode { this.expression = expression; this.block = block; } + + public void test() { + return; + + } + + @Override + public TypeCheckResult accept(SemanticVisitor visitor) { + return null; + } } diff --git a/src/main/java/parser/astBuilder/ASTBuilder.java b/src/main/java/parser/astBuilder/ASTBuilder.java index 224b59d..bf84fd4 100644 --- a/src/main/java/parser/astBuilder/ASTBuilder.java +++ b/src/main/java/parser/astBuilder/ASTBuilder.java @@ -108,6 +108,8 @@ public class ASTBuilder extends SimpleJavaBaseVisitor { return visitBlockStatement(ctx.blockStatement()); } else if(ctx.whileStatement() != null) { return visitWhileStatement(ctx.whileStatement()); + } else if(ctx.doWhileStatement() != null) { + return visitDoWhileStatement(ctx.doWhileStatement()); } else if(ctx.forStatement() != null) { return visitForStatement(ctx.forStatement()); } else if(ctx.ifElseStatement() != null) { @@ -131,10 +133,15 @@ public class ASTBuilder extends SimpleJavaBaseVisitor { @Override public ASTNode visitBlockStatement(SimpleJavaParser.BlockStatementContext ctx) { BlockNode blockNode = new BlockNode(); + boolean hasReturnStatement = false; for(SimpleJavaParser.StatementContext statement : ctx.statement()) { - blockNode.addStatement((IStatementNode) visit(statement)); + IStatementNode statementNode = (IStatementNode) visit(statement); + if(statementNode instanceof ReturnNode) { + hasReturnStatement = true; + } + blockNode.addStatement(statementNode); } - if(!blockNode.hasReturnStatement) { + if(!hasReturnStatement) { blockNode.addStatement(new ReturnNode(null)); } return blockNode; @@ -161,28 +168,30 @@ public class ASTBuilder extends SimpleJavaBaseVisitor { @Override public ASTNode visitForStatement(SimpleJavaParser.ForStatementContext ctx) { - List statements = new ArrayList<>(); + List statements = new ArrayList<>(); //init - if(ctx.statementExpression(0) != null){ - statements.add((StatementNode) visit(ctx.statementExpression(0))); - } else if (ctx.localVariableDeclaration() != null) { - statements.add((StatementNode) visit(ctx.localVariableDeclaration())); + int i = 0; + if(ctx.localVariableDeclaration() != null) { + statements.add((IStatementNode) visit(ctx.localVariableDeclaration())); + } else if(ctx.statementExpression(i) != null){ + statements.add((IStatementNode) visit(ctx.statementExpression(i))); + i++; } //condition IExpressionNode condition = (IExpressionNode) visit(ctx.expression()); //ink - IStatementNode increment = null; - if(ctx.statementExpression(1) != null){ - increment = (IStatementNode) visit(ctx.statementExpression(1)); + IStatementNode crement = null; + if(ctx.statementExpression(i) != null){ + crement = (IStatementNode) visit(ctx.statementExpression(i)); } BlockNode forBlock = (BlockNode) visit(ctx.blockStatement()); - if(increment != null){ - forBlock.addStatement((increment)); + if(crement != null){ + forBlock.addStatement((crement)); } WhileNode While = new WhileNode(condition, forBlock); @@ -190,7 +199,7 @@ public class ASTBuilder extends SimpleJavaBaseVisitor { statements.add(While); BlockNode resultBlock = new BlockNode(); - for(StatementNode statement : statements) { + for(IStatementNode statement : statements) { resultBlock.addStatement((IStatementNode) statement); } diff --git a/src/main/resources/input/CompilerInput.java b/src/main/resources/input/CompilerInput.java index d850a3e..825490d 100644 --- a/src/main/resources/input/CompilerInput.java +++ b/src/main/resources/input/CompilerInput.java @@ -1,16 +1,14 @@ -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; - } +public class Compiler { + public int add(int i, int j) { + return i+j; + } +} + +public class Node { + public void main() { + Compiler compiler = new Compiler(); + int i = compiler.add(5, 8); + return i; } } From 85ae06048cd6b69bf545208c118dbcd16161eb2d Mon Sep 17 00:00:00 2001 From: i22035 Date: Thu, 27 Jun 2024 18:55:28 +0200 Subject: [PATCH 09/10] Add Return if Returntype is Void --- src/main/java/parser/astBuilder/ASTBuilder.java | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/src/main/java/parser/astBuilder/ASTBuilder.java b/src/main/java/parser/astBuilder/ASTBuilder.java index bf84fd4..b6d8283 100644 --- a/src/main/java/parser/astBuilder/ASTBuilder.java +++ b/src/main/java/parser/astBuilder/ASTBuilder.java @@ -60,13 +60,16 @@ public class ASTBuilder extends SimpleJavaBaseVisitor { constructorNode.addParameter((ParameterNode) visit(parameter)); } } + constructorNode.block.addStatement(new ReturnNode(null)); return constructorNode; } @Override public ASTNode visitMethodDeclaration(SimpleJavaParser.MethodDeclarationContext ctx) { if(ctx.MainMethodDeclaration() != null) { - return new MainMethodNode((BlockNode) visit(ctx.blockStatement())); + MainMethodNode mainMethod = new MainMethodNode((BlockNode) visit(ctx.blockStatement())); + mainMethod.block.addStatement(new ReturnNode(null)); + return mainMethod; } else { if(ctx.type() != null) { MethodNode methodNode = new MethodNode(ctx.AccessModifier().getText(), createTypeNode(ctx.type().getText()), false, ctx.Identifier().getText(), (BlockNode) visit(ctx.blockStatement())); @@ -83,6 +86,7 @@ public class ASTBuilder extends SimpleJavaBaseVisitor { methodNode.addParameter((ParameterNode) visit(parameter)); } } + methodNode.block.addStatement(new ReturnNode(null)); return methodNode; } } @@ -133,16 +137,8 @@ public class ASTBuilder extends SimpleJavaBaseVisitor { @Override public ASTNode visitBlockStatement(SimpleJavaParser.BlockStatementContext ctx) { BlockNode blockNode = new BlockNode(); - boolean hasReturnStatement = false; for(SimpleJavaParser.StatementContext statement : ctx.statement()) { - IStatementNode statementNode = (IStatementNode) visit(statement); - if(statementNode instanceof ReturnNode) { - hasReturnStatement = true; - } - blockNode.addStatement(statementNode); - } - if(!hasReturnStatement) { - blockNode.addStatement(new ReturnNode(null)); + blockNode.addStatement((IStatementNode) visit(statement)); } return blockNode; } From 27f50b9c6622fd20f9c55aa43d9d14aa33d0c164 Mon Sep 17 00:00:00 2001 From: Purplumbi504 Date: Thu, 27 Jun 2024 21:14:02 +0200 Subject: [PATCH 10/10] Adding EmptyClass Test AST --- src/main/java/ast/ClassNode.java | 16 +-- .../java/parser/astBuilder/ASTBuilder.java | 25 +++- .../generated/SimpleJavaBaseListener.java | 2 +- .../generated/SimpleJavaBaseVisitor.java | 2 +- .../parser/generated/SimpleJavaLexer.java | 2 +- .../parser/generated/SimpleJavaListener.java | 2 +- .../parser/generated/SimpleJavaParser.java | 2 +- .../parser/generated/SimpleJavaVisitor.java | 2 +- src/test/java/parser/AstBuilderTest.java | 108 +++++------------- .../resources/input/javaCases/EmptyClass.java | 1 + .../input/javaCases/MultipleClasses.java | 7 ++ 11 files changed, 66 insertions(+), 103 deletions(-) create mode 100644 src/test/resources/input/javaCases/EmptyClass.java create mode 100644 src/test/resources/input/javaCases/MultipleClasses.java diff --git a/src/main/java/ast/ClassNode.java b/src/main/java/ast/ClassNode.java index 63dfed2..61134ab 100644 --- a/src/main/java/ast/ClassNode.java +++ b/src/main/java/ast/ClassNode.java @@ -15,30 +15,20 @@ public class ClassNode implements ASTNode, Visitable { public AccessModifierNode accessType; public String identifier; public List members = new ArrayList<>(); - public boolean hasConstructor; - public ClassNode() {} + public ClassNode(){ + + } public ClassNode(String accessType, String identifier){ this.accessType = new AccessModifierNode(accessType); this.identifier = identifier; - hasConstructor = false; } public void addMember(MemberNode member) { - if (member instanceof ConstructorNode) { - this.hasConstructor = true; - } members.add(member); } - public void ensureConstructor(){ - if(!hasConstructor) { - ConstructorNode constructor = new ConstructorNode(new AccessModifierNode("public"), identifier); - members.addFirst(constructor); - } - } - public List getMethods(){ List methods = new ArrayList<>(); for (MemberNode member : members) { diff --git a/src/main/java/parser/astBuilder/ASTBuilder.java b/src/main/java/parser/astBuilder/ASTBuilder.java index b6d8283..32137eb 100644 --- a/src/main/java/parser/astBuilder/ASTBuilder.java +++ b/src/main/java/parser/astBuilder/ASTBuilder.java @@ -44,11 +44,28 @@ public class ASTBuilder extends SimpleJavaBaseVisitor { @Override public ASTNode visitClassDeclaration(SimpleJavaParser.ClassDeclarationContext ctx) { - ClassNode classNode = new ClassNode(ctx.AccessModifier().getText(), ctx.Identifier().getText()); - for (SimpleJavaParser.MemberDeclarationContext member : ctx.memberDeclaration()) { - classNode.addMember((MemberNode) visit(member)); + ClassNode classNode; + if(ctx.AccessModifier() != null){ + classNode = new ClassNode(ctx.AccessModifier().getText(), ctx.Identifier().getText()); } - classNode.ensureConstructor(); + else{ + classNode = new ClassNode("public", ctx.Identifier().getText()); + } + + boolean hasConstructor = false; + + for (SimpleJavaParser.MemberDeclarationContext member : ctx.memberDeclaration()) { + MemberNode memberNode = (MemberNode) visit(member); + if(memberNode instanceof ConstructorNode){ + hasConstructor = true; + } + classNode.addMember(memberNode); + } + + if(!hasConstructor){ + classNode.members.addFirst(new ConstructorNode(new AccessModifierNode("public"), ctx.Identifier().getText())); + } + return classNode; } diff --git a/src/main/java/parser/generated/SimpleJavaBaseListener.java b/src/main/java/parser/generated/SimpleJavaBaseListener.java index 5cc0d6c..eecc12f 100644 --- a/src/main/java/parser/generated/SimpleJavaBaseListener.java +++ b/src/main/java/parser/generated/SimpleJavaBaseListener.java @@ -1,4 +1,4 @@ -// Generated from C:/Users/Maxi/Documents/DHBW/Compilerbau/NichtHaskell2.0/src/main/java/parser/grammar/SimpleJava.g4 by ANTLR 4.13.1 +// Generated from C:/Users/janni/Desktop/NichtHaskell2.0/src/main/java/parser/grammar/SimpleJava.g4 by ANTLR 4.13.1 package parser.generated; import org.antlr.v4.runtime.ParserRuleContext; diff --git a/src/main/java/parser/generated/SimpleJavaBaseVisitor.java b/src/main/java/parser/generated/SimpleJavaBaseVisitor.java index 97b6b28..b3a6029 100644 --- a/src/main/java/parser/generated/SimpleJavaBaseVisitor.java +++ b/src/main/java/parser/generated/SimpleJavaBaseVisitor.java @@ -1,4 +1,4 @@ -// Generated from C:/Users/Maxi/Documents/DHBW/Compilerbau/NichtHaskell2.0/src/main/java/parser/grammar/SimpleJava.g4 by ANTLR 4.13.1 +// Generated from C:/Users/janni/Desktop/NichtHaskell2.0/src/main/java/parser/grammar/SimpleJava.g4 by ANTLR 4.13.1 package parser.generated; import org.antlr.v4.runtime.tree.AbstractParseTreeVisitor; diff --git a/src/main/java/parser/generated/SimpleJavaLexer.java b/src/main/java/parser/generated/SimpleJavaLexer.java index 51b5bfc..23296ee 100644 --- a/src/main/java/parser/generated/SimpleJavaLexer.java +++ b/src/main/java/parser/generated/SimpleJavaLexer.java @@ -1,4 +1,4 @@ -// Generated from C:/Users/Maxi/Documents/DHBW/Compilerbau/NichtHaskell2.0/src/main/java/parser/grammar/SimpleJava.g4 by ANTLR 4.13.1 +// Generated from C:/Users/janni/Desktop/NichtHaskell2.0/src/main/java/parser/grammar/SimpleJava.g4 by ANTLR 4.13.1 package parser.generated; import org.antlr.v4.runtime.Lexer; import org.antlr.v4.runtime.CharStream; diff --git a/src/main/java/parser/generated/SimpleJavaListener.java b/src/main/java/parser/generated/SimpleJavaListener.java index 3e7bf6d..580bfe1 100644 --- a/src/main/java/parser/generated/SimpleJavaListener.java +++ b/src/main/java/parser/generated/SimpleJavaListener.java @@ -1,4 +1,4 @@ -// Generated from C:/Users/Maxi/Documents/DHBW/Compilerbau/NichtHaskell2.0/src/main/java/parser/grammar/SimpleJava.g4 by ANTLR 4.13.1 +// Generated from C:/Users/janni/Desktop/NichtHaskell2.0/src/main/java/parser/grammar/SimpleJava.g4 by ANTLR 4.13.1 package parser.generated; import org.antlr.v4.runtime.tree.ParseTreeListener; diff --git a/src/main/java/parser/generated/SimpleJavaParser.java b/src/main/java/parser/generated/SimpleJavaParser.java index cff16d5..3a80a6a 100644 --- a/src/main/java/parser/generated/SimpleJavaParser.java +++ b/src/main/java/parser/generated/SimpleJavaParser.java @@ -1,4 +1,4 @@ -// Generated from C:/Users/Maxi/Documents/DHBW/Compilerbau/NichtHaskell2.0/src/main/java/parser/grammar/SimpleJava.g4 by ANTLR 4.13.1 +// Generated from C:/Users/janni/Desktop/NichtHaskell2.0/src/main/java/parser/grammar/SimpleJava.g4 by ANTLR 4.13.1 package parser.generated; import org.antlr.v4.runtime.atn.*; import org.antlr.v4.runtime.dfa.DFA; diff --git a/src/main/java/parser/generated/SimpleJavaVisitor.java b/src/main/java/parser/generated/SimpleJavaVisitor.java index 5d66eae..beefef9 100644 --- a/src/main/java/parser/generated/SimpleJavaVisitor.java +++ b/src/main/java/parser/generated/SimpleJavaVisitor.java @@ -1,4 +1,4 @@ -// Generated from C:/Users/Maxi/Documents/DHBW/Compilerbau/NichtHaskell2.0/src/main/java/parser/grammar/SimpleJava.g4 by ANTLR 4.13.1 +// Generated from C:/Users/janni/Desktop/NichtHaskell2.0/src/main/java/parser/grammar/SimpleJava.g4 by ANTLR 4.13.1 package parser.generated; import org.antlr.v4.runtime.tree.ParseTreeVisitor; diff --git a/src/test/java/parser/AstBuilderTest.java b/src/test/java/parser/AstBuilderTest.java index b5bec24..de3f40b 100644 --- a/src/test/java/parser/AstBuilderTest.java +++ b/src/test/java/parser/AstBuilderTest.java @@ -1,103 +1,51 @@ package parser; + +import ast.ASTNode; import ast.ClassNode; import ast.ProgramNode; +import ast.members.ConstructorNode; +import ast.members.MemberNode; +import ast.type.AccessModifierNode; 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 org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import parser.astBuilder.ASTBuilder; import parser.generated.SimpleJavaLexer; import parser.generated.SimpleJavaParser; -import static org.junit.jupiter.api.Assertions.assertEquals; +import java.io.IOException; -public class AstBuilderTest { +import static org.assertj.core.api.Assertions.assertThat; + +@DisplayName("Untyped Abstract Syntax Tree") +class AstBuilderTest { @Test - public void astBuilderTest() { - // ---------------- Leere Klasse nachgebaut ---------------- + public void emptyClassTest(){ + MemberNode constructor = new ConstructorNode(new AccessModifierNode("public"),"EmptyClass"); + ClassNode emptyClass = new ClassNode("public", "EmptyClass"); + emptyClass.addMember(constructor); + var expected = new ProgramNode(); + expected.addClass(emptyClass); - ProgramNode expectedASTEmptyClass = new ProgramNode(); - - // public class Name {} - ClassNode nameClass = new ClassNode("public", "Name"); - - expectedASTEmptyClass.addClass(nameClass); - - - // ---------------- Leere Klasse erzeugt ---------------- - - // init - CharStream inputCharStream = CharStreams.fromString("public class Name {}"); - SimpleJavaLexer lexer = new SimpleJavaLexer(inputCharStream); + CharStream testFile = null; + try { + testFile = CharStreams.fromFileName("src/test/resources/input/javaCases/EmptyClass.java"); + } catch (IOException e) { + throw new RuntimeException(e); + } + SimpleJavaLexer lexer = new SimpleJavaLexer(testFile); CommonTokenStream tokenStream = new CommonTokenStream(lexer); tokenStream.fill(); - - /* Parser -> Parsetree */ SimpleJavaParser parser = new SimpleJavaParser(tokenStream); - ParseTree parseTreeEmptyClass = parser.program(); // parse the input - - /* AST builder -> AST */ + ParseTree parseTree = parser.program(); ASTBuilder astBuilder = new ASTBuilder(); - ProgramNode actualASTEmptyClass = (ProgramNode) new ASTBuilder().visit(parseTreeEmptyClass); + var actual = astBuilder.visit(parseTree); - - // ---------------- Vergleichen ---------------- - - String expectedASTasString = expectedASTEmptyClass.toString(); - String actualASTasString = new ASTBuilder().visit(parseTreeEmptyClass).toString(); - - // Wie vergleiche ich das? - assertEquals(expectedASTasString, actualASTasString); - assertEquals(expectedASTEmptyClass, actualASTEmptyClass); + assertThat(actual).isEqualToComparingFieldByFieldRecursively(expected); } - - - - - - - - - - - - - - - // ---------------- Alter CompilerInput nachgebaut ---------------- - // ProgramNode startNode = new ProgramNode(); - // public class CompilerInput {} - // ClassNode compilerInputClass = new ClassNode(new AccessTypeNode(EnumAccessTypeNode.PUBLIC), "CompilerInput"); - // public int a; - // compilerInputClass.addMember(new FieldNode(new AccessTypeNode(EnumAccessTypeNode.PUBLIC), new BaseTypeNode(EnumTypeNode.INT), "a")); - // public static int testMethod(char x) { return 0; } - /* compilerInputClass.addMember( - new MethodNode( - new AccessTypeNode(EnumAccessTypeNode.PUBLIC), - new BaseTypeNode(EnumTypeNode.INT), - "testMethod", - new ParameterListNode(List.of(new ParameterNode(new BaseTypeNode(EnumTypeNode.CHAR), "x"))), - List.of(new ReturnStatementNode(new LiteralNode(0))) - )); - - ClassNode testClass = new ClassNode(new AccessTypeNode(EnumAccessTypeNode.PUBLIC), "Test"); - testClass.addMember( - new MethodNode( - new AccessTypeNode(EnumAccessTypeNode.PUBLIC), - new BaseTypeNode(EnumTypeNode.INT), - "testMethod", - new ParameterListNode(List.of(new ParameterNode(new BaseTypeNode(EnumTypeNode.CHAR), "x"), new ParameterNode(new BaseTypeNode(EnumTypeNode.INT), "a"))), - List.of(new ReturnStatementNode(new LiteralNode(0))) - ) - ); - - */ - - //compilerInputClass.addClass(testClass); - - // startNode.addClass(compilerInputClass); - // startNode.addClass(testClass); -} +} \ No newline at end of file diff --git a/src/test/resources/input/javaCases/EmptyClass.java b/src/test/resources/input/javaCases/EmptyClass.java new file mode 100644 index 0000000..393c29c --- /dev/null +++ b/src/test/resources/input/javaCases/EmptyClass.java @@ -0,0 +1 @@ +class EmptyClass { } \ No newline at end of file diff --git a/src/test/resources/input/javaCases/MultipleClasses.java b/src/test/resources/input/javaCases/MultipleClasses.java new file mode 100644 index 0000000..8f8e5c7 --- /dev/null +++ b/src/test/resources/input/javaCases/MultipleClasses.java @@ -0,0 +1,7 @@ +class EmptyClass1{ + +} + +class EmptyClass2{ + +} \ No newline at end of file