From 8cd22c6e4c3cd714eb453a488dd023e8cdf546ad Mon Sep 17 00:00:00 2001 From: Bruder John Date: Sun, 23 Jun 2024 20:57:53 +0200 Subject: [PATCH 01/11] Removed some Exercices from Tests because parser is not ready for --- src/test/resources/semantic/endToTAST/CorrectTest.java | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/test/resources/semantic/endToTAST/CorrectTest.java b/src/test/resources/semantic/endToTAST/CorrectTest.java index 054a49b..1efa68d 100644 --- a/src/test/resources/semantic/endToTAST/CorrectTest.java +++ b/src/test/resources/semantic/endToTAST/CorrectTest.java @@ -4,15 +4,8 @@ public class Example { public static int testMethod(int b, boolean bo){ a = b; - if(bo){ - - } return a; } - public static void testMethod(int b){ - - } - } \ No newline at end of file From 8163d0b61ece1b568e0ecdd7e8b0244662da6f4f Mon Sep 17 00:00:00 2001 From: Bruder John Date: Wed, 26 Jun 2024 09:55:12 +0200 Subject: [PATCH 02/11] removing Semantic Tests --- src/test/java/semantic/Mocker.java | 102 -------------- src/test/java/semantic/SemanticTest.java | 114 --------------- .../resources/semantic/correctRefType.json | 70 --------- .../resources/semantic/refTypeMismatch.json | 133 ------------------ src/test/resources/semantic/test.json | 1 - 5 files changed, 420 deletions(-) delete mode 100644 src/test/java/semantic/Mocker.java delete mode 100644 src/test/java/semantic/SemanticTest.java delete mode 100644 src/test/resources/semantic/correctRefType.json delete mode 100644 src/test/resources/semantic/refTypeMismatch.json delete mode 100644 src/test/resources/semantic/test.json diff --git a/src/test/java/semantic/Mocker.java b/src/test/java/semantic/Mocker.java deleted file mode 100644 index 683b385..0000000 --- a/src/test/java/semantic/Mocker.java +++ /dev/null @@ -1,102 +0,0 @@ -package semantic; - -import ast.*; -import ast.members.FieldNode; -import ast.members.MethodNode; -import ast.parameters.ParameterNode; -import ast.type.AccessModifierNode; -import ast.type.type.*; - -public class Mocker { - - public static ASTNode mockTwoSameFields(){ - ProgramNode p = new ProgramNode(); - - ClassNode c = new ClassNode(); - c.identifier = "testClass"; - - FieldNode f1 = new FieldNode(new AccessModifierNode("public"), new BaseType(TypeEnum.INT), "a"); - - c.members.add(f1); - - FieldNode f2 = new FieldNode(new AccessModifierNode("public"), new BaseType(TypeEnum.INT), "a"); - - c.members.add(f2); - - p.classes.add(c); - return p; - } - - public static ASTNode mockSimpleMethod(){ - ProgramNode p = new ProgramNode(); - - ClassNode c = new ClassNode(); - - MethodNode methodNode = new MethodNode(); - - //Parameter - ParameterNode parameterNode = new ParameterNode(new BaseType(TypeEnum.INT), "a"); - - methodNode.addParameter(parameterNode); - - //Statements - - //Block - methodNode.block = new ast.statements.BlockNode(); - - c.members.add(methodNode); - - p.classes.add(c); - - return p; - } - - public static ASTNode mockTwoSameMethods(){ - ProgramNode p = new ProgramNode(); - - ClassNode c = new ClassNode(); - - MethodNode methodNode = new MethodNode(); - methodNode.block = new ast.statements.BlockNode(); - methodNode.setType(new BaseType(TypeEnum.INT)); - - methodNode.setIdentifier("testMethod"); - - c.members.add(methodNode); - - MethodNode methodNode1 = new MethodNode(); - methodNode1.block = new ast.statements.BlockNode(); - methodNode1.setType(new BaseType(TypeEnum.INT)); - - methodNode1.setIdentifier("testMethod"); - - c.members.add(methodNode1); - - p.classes.add(c); - - return p; - } - - public static ASTNode mockTwoDifferentMethods(){ - ProgramNode p = new ProgramNode(); - - ClassNode c = new ClassNode(); - - MethodNode methodNode = new MethodNode(); - methodNode.block = new ast.statements.BlockNode(); - methodNode.setIdentifier("testMethod"); - - c.members.add(methodNode); - - MethodNode methodNode1 = new MethodNode(); - methodNode1.block = new ast.statements.BlockNode(); - methodNode1.setIdentifier("testMethod1"); - - c.members.add(methodNode1); - - p.classes.add(c); - - return p; - } - -} diff --git a/src/test/java/semantic/SemanticTest.java b/src/test/java/semantic/SemanticTest.java deleted file mode 100644 index 7b8ad6a..0000000 --- a/src/test/java/semantic/SemanticTest.java +++ /dev/null @@ -1,114 +0,0 @@ -package semantic; - -import ast.*; -import ast.members.FieldNode; -import ast.members.MemberNode; -import ast.members.MethodNode; -import ast.parameters.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 { - - -// @Test -// public void alreadyDeclaredLocalFieldVar() { -// ProgramNode programNode = new ProgramNode(); -// List classList = new ArrayList<>(); -// AccessTypeNode accessTypeNode = new AccessTypeNode(EnumAccessTypeNode.PUBLIC); -// ClassNode classNode = new ClassNode(accessTypeNode, "testClass"); -// -// SemanticAnalyzer semanticAnalyzer = new SemanticAnalyzer(); -// ASTNode tast = semanticAnalyzer.generateTast(ast); -// -// MemberNode memberNode2 = new FieldNode(accessTypeNode, new BaseTypeNode(EnumTypeNode.INT), "testVar"); -// classNode.members.add(memberNode2); -// -// classList.add(classNode); -// programNode.classes = classList; -// -// ASTNode typedAst = SemanticAnalyzer.generateTast(programNode); -// -// assertEquals(1, SemanticAnalyzer.errors.size()); -// assertInstanceOf(AlreadyDeclearedException.class, SemanticAnalyzer.errors.getFirst()); -// assertNull(typedAst); -// } -// -// @Test -// public void shouldWorkWithNoError() { -// ProgramNode programNode = new ProgramNode(); -// List classList = new ArrayList<>(); -// AccessTypeNode accessTypeNode = new AccessTypeNode(EnumAccessTypeNode.PUBLIC); -// ClassNode classNode = new ClassNode(accessTypeNode, "testClass"); -// -// SemanticAnalyzer semanticAnalyzer = new SemanticAnalyzer(); -// ASTNode tast = semanticAnalyzer.generateTast(ast); -// -// assertEquals(semanticAnalyzer.errors.size(), 0); -// assertNotNull(tast); -// -// MemberNode memberNode3 = getMemberNode(accessTypeNode); -// classNode.members.add(memberNode3); -// -// classList.add(classNode); -// programNode.classes = classList; -// -// ASTNode typedAst = SemanticAnalyzer.generateTast(programNode); -// -// assertEquals(0, SemanticAnalyzer.errors.size()); -// assertEquals(programNode, typedAst); -// } -// -// /** -// * This method is used to create a MemberNode representing a method. -// * It first creates a list of ParameterNodes and adds a ParameterNode to it. -// * Then, it creates a ParameterListNode using the list of ParameterNodes. -// * After that, it creates a list of StatementNodes and adds a StatementNode to it by calling the getStatementNode method. -// * Finally, it creates a MethodNode using the provided AccessTypeNode, a BaseTypeNode representing the return type of the method, -// * the method name, the ParameterListNode, and the list of StatementNodes, and returns this MethodNode. -// * -// * @param accessTypeNode The AccessTypeNode representing the access type of the method. -// * @return The created MemberNode representing the method. -// */ -//private static MemberNode getMemberNode(AccessTypeNode accessTypeNode) { -// List parameterNodeList = new ArrayList<>(); -// ParameterNode parameterNode1 = new ParameterNode(new BaseTypeNode(EnumTypeNode.INT), "param1"); -// parameterNodeList.add(parameterNode1); -// ParameterListNode parameterListNode = new ParameterListNode(parameterNodeList); -// -// List statementNodeList = new ArrayList<>(); -// -// StatementNode statementNode1 = getStatementNode(); -// statementNodeList.add(statementNode1); -// -// return new MethodNode(accessTypeNode, new BaseTypeNode(EnumTypeNode.INT), "testVar2", parameterListNode, statementNodeList); -//} -// -// /** -// * This method is used to create a StatementNode for an assignment operation. -// * It first creates two IdentifierExpressionNodes for 'this' and 'objectVar'. -// * Then, it creates a BinaryExpressionNode to represent the operation 'this.objectVar'. -// * After that, it creates a LiteralNode to represent the integer value 1. -// * Finally, it creates another BinaryExpressionNode to represent the assignment operation 'this.objectVar = 1', -// * and wraps this expression in an AssignmentStatementNode. -// * -// * @return The created AssignmentStatementNode representing the assignment operation 'this.objectVar = 1'. -// */ -//private static StatementNode getStatementNode() { -// ExpressionNode expressionNodeObjectVariableLeft = new IdentifierExpressionNode("this"); -// ExpressionNode expressionNodeObjectVariableRight = new IdentifierExpressionNode("objectVar"); -// -// ExpressionNode expressionNodeLeft = new BinaryExpressionNode(expressionNodeObjectVariableLeft, expressionNodeObjectVariableRight, ExpresssionOperator.DOT); -// -// ExpressionNode expressionNodeRight = new LiteralNode(1); -// -// BinaryExpressionNode expressionNode = new BinaryExpressionNode(expressionNodeLeft, expressionNodeRight, ExpresssionOperator.ASSIGNMENT); -// -// return new AssignmentStatementNode(expressionNode); -//} -} diff --git a/src/test/resources/semantic/correctRefType.json b/src/test/resources/semantic/correctRefType.json deleted file mode 100644 index 7e67bbc..0000000 --- a/src/test/resources/semantic/correctRefType.json +++ /dev/null @@ -1,70 +0,0 @@ -{ - "classes": [ - { - "identifier": "testClass1", - "accessType": { - "enumAccessTypeNode": "PUBLIC" - }, - "members": [ - { - "@type": "Field", - "accessTypeNode": { - "enumAccessTypeNode": "PUBLIC" - }, - "type": { - "@type": "Base", - "enumType": "INT" - }, - "identifier": "testVar1" - }, - { - "@type": "Method", - "visibility": { - "enumAccessTypeNode": "PUBLIC" - }, - "type": { - "@type": "Base", - "enumType": "INT" - }, - "identifier": "testMethod", - "parameters": { - "parameters": [ - { - "type": { - "@type": "Base", - "enumType": "INT" - }, - "identifier": "param1" - } - ] - }, - "statements": [ - { - "@type": "Assignment", - "expressionLeft": { - "@type": "InstVar", - "identifier": "testVar1", - "expression": { - "@type": "This", - "type": { - "@type": "Reference", - "identifier": "testClass1" - } - }, - "type": null - }, - "expressionRight": { - "@type": "Literal", - "type": { - "@type": "Base", - "enumType": "INT" - } - } - } - ] - } - ], - "hasConstructor": false - } - ] -} \ No newline at end of file diff --git a/src/test/resources/semantic/refTypeMismatch.json b/src/test/resources/semantic/refTypeMismatch.json deleted file mode 100644 index e5ebcd3..0000000 --- a/src/test/resources/semantic/refTypeMismatch.json +++ /dev/null @@ -1,133 +0,0 @@ -{ - "classes": [ - { - "identifier": "testClass1", - "accessType": { - "enumAccessTypeNode": "PUBLIC" - }, - "members": [ - { - "@type": "Field", - "accessTypeNode": { - "enumAccessTypeNode": "PUBLIC" - }, - "type": { - "@type": "Base", - "enumType": "INT" - }, - "identifier": "testVar1" - }, - { - "@type": "Method", - "visibility": { - "enumAccessTypeNode": "PUBLIC" - }, - "type": { - "@type": "Base", - "enumType": "INT" - }, - "identifier": "testMethod", - "parameters": { - "parameters": [ - { - "type": { - "@type": "Base", - "enumType": "INT" - }, - "identifier": "param1" - } - ] - }, - "statements": [ - { - "@type": "Assignment", - "expressionLeft": { - "@type": "InstVar", - "identifier": "testVar1", - "expression": { - "@type": "This", - "type": { - "@type": "Reference", - "identifier": "testClass1" - } - }, - "type": null - }, - "expressionRight": { - "@type": "Literal", - "type": { - "@type": "Base", - "enumType": "BOOLEAN" - } - } - } - ] - } - ], - "hasConstructor": false, - "methods": [ - { - "@type": "Method", - "visibility": { - "enumAccessTypeNode": "PUBLIC" - }, - "type": { - "@type": "Base", - "enumType": "INT" - }, - "identifier": "testMethod", - "parameters": { - "parameters": [ - { - "type": { - "@type": "Base", - "enumType": "INT" - }, - "identifier": "param1" - } - ] - }, - "statements": [ - { - "@type": "Assignment", - "expressionLeft": { - "@type": "InstVar", - "identifier": "testVar", - "expression": { - "@type": "InstVar", - "identifier": "testVar", - "expression": { - "@type": "This", - "type": { - "@type": "Reference", - "identifier": "testClass2" - } - }, - "type": null - }, - "type": null - }, - "expressionRight": { - "@type": "Literal", - "type": null - }, - "type": null - }, - { - "@type": "VariableDeclaration", - "type": { - "@type": "Base", - "enumType": "CHAR" - }, - "identifier": "objectVar", - "expression": { - "@type": "Literal", - "type": null - } - } - ] - } - ] - } - ] -} \ No newline at end of file diff --git a/src/test/resources/semantic/test.json b/src/test/resources/semantic/test.json deleted file mode 100644 index 7acc30f..0000000 --- a/src/test/resources/semantic/test.json +++ /dev/null @@ -1 +0,0 @@ -{"classes":[{"identifier":"testClass","accessType":{"enumAccessTypeNode":"PUBLIC"},"members":[{"@type":"Field","accessTypeNode":{"enumAccessTypeNode":"PUBLIC"},"type":{"@type":"Base","enumType":"INT"},"identifier":"testVar1"},{"@type":"Field","accessTypeNode":{"enumAccessTypeNode":"PUBLIC"},"type":{"@type":"Base","enumType":"INT"},"identifier":"objectVar"},{"@type":"Method","visibility":{"enumAccessTypeNode":"PUBLIC"},"type":{"@type":"Base","enumType":"INT"},"identifier":"testVar2","parameters":{"parameters":[{"type":{"@type":"Base","enumType":"INT"},"identifier":"param1"}]},"statements":[{"@type":"Assignment","expressionLeft":{"@type":"InstVar","identifier":"objectVar","expression":{"@type":"This","type":{"@type":"Reference","identifier":"testClass"}},"type":null},"expressionRight":{"@type":"Literal","type":{"@type":"Base","enumType":"INT"}}}]}],"hasConstructor":false,"methods":[{"@type":"Method","visibility":{"enumAccessTypeNode":"PUBLIC"},"type":{"@type":"Base","enumType":"INT"},"identifier":"testVar2","parameters":{"parameters":[{"type":{"@type":"Base","enumType":"INT"},"identifier":"param1"}]},"statements":[{"@type":"Assignment","expressionLeft":{"@type":"InstVar","identifier":"objectVar","expression":{"@type":"This","type":{"@type":"Reference","identifier":"testClass"}},"type":null},"expressionRight":{"@type":"Literal","type":{"@type":"Base","enumType":"INT"}}}]}]}]} \ No newline at end of file From 35b3e9ee462641ef7d2e2458587add0fffc43218 Mon Sep 17 00:00:00 2001 From: Bruder John Date: Thu, 27 Jun 2024 08:11:17 +0200 Subject: [PATCH 03/11] Added Some Semantice Checks --- src/main/java/semantic/SemanticAnalyzer.java | 80 ++++++++++++++----- .../java/semantic/context/ClassContext.java | 10 +++ src/main/java/semantic/context/Context.java | 4 + .../exeptions/NotDefinedException.java | 9 +++ src/test/java/semantic/EndToTAST.java | 26 +----- .../semantic/endToTAST/CorrectTest.java | 33 +++++++- .../semantic/endToTAST/WrongIfClause.java | 7 -- 7 files changed, 116 insertions(+), 53 deletions(-) create mode 100644 src/main/java/semantic/exeptions/NotDefinedException.java delete mode 100644 src/test/resources/semantic/endToTAST/WrongIfClause.java diff --git a/src/main/java/semantic/SemanticAnalyzer.java b/src/main/java/semantic/SemanticAnalyzer.java index 4fc169a..92e69b2 100644 --- a/src/main/java/semantic/SemanticAnalyzer.java +++ b/src/main/java/semantic/SemanticAnalyzer.java @@ -150,6 +150,9 @@ public class SemanticAnalyzer implements SemanticVisitor { if (resultType == null) { resultType = new BaseType(TypeEnum.VOID); } + if(methodNode.getType() == null){ + methodNode.setType(new BaseType(TypeEnum.VOID)); + } if (!resultType.equals(methodNode.getType())) { errors.add(new TypeMismatchException("Method-Declaration " + methodNode.getIdentifier() + " with type " + methodNode.getType() + " has at least one Mismatching return Type:")); @@ -179,13 +182,13 @@ public class SemanticAnalyzer implements SemanticVisitor { @Override public TypeCheckResult analyze(ReturnNode toCheck) { - - if(toCheck.expression != null){ + if (toCheck.expression != null) { var result = toCheck.expression.accept(this); return new TypeCheckResult(true, result.getType()); - } else { - return new TypeCheckResult(false, null); + } else if(toCheck.voidReturn){ + return new TypeCheckResult(false, new BaseType(TypeEnum.VOID)); } + return new TypeCheckResult(true, null); } @@ -206,8 +209,8 @@ public class SemanticAnalyzer implements SemanticVisitor { ITypeNode blockReturnType = null; for (IStatementNode statementNode : blockNode.statements) { var result = statementNode.accept(this); - if(result.getType() != null){ - if(blockReturnType == null){ + if (result.getType() != null) { + if (blockReturnType == null) { blockReturnType = result.getType(); } else { errors.add(new MultipleReturnTypes("There are multiple Return types")); @@ -219,7 +222,14 @@ public class SemanticAnalyzer implements SemanticVisitor { @Override public TypeCheckResult analyze(AssignableNode toCheck) { - return new TypeCheckResult(true, currentFields.get(toCheck.identifier)); + + if ( currentFields.get(toCheck.identifier) != null){ + return new TypeCheckResult(true, currentFields.get(toCheck.identifier)); + } else if (currentScope.getLocalVar(toCheck.identifier) != null) { + return new TypeCheckResult(true, currentScope.getLocalVar(toCheck.identifier)); + } + + return new TypeCheckResult(true, null); } @@ -228,11 +238,6 @@ public class SemanticAnalyzer implements SemanticVisitor { return null; } - /*@Override - public TypeCheckResult analyze(ForNode toCheck) { - return null; - }*/ - @Override public TypeCheckResult analyze(AssignNode toCheck) { AssignableNode assignable = toCheck.assignable; @@ -258,7 +263,12 @@ public class SemanticAnalyzer implements SemanticVisitor { currentNullType = lResult.getType(); var rResult = rExpression.accept(this); - if (!Objects.equals(currentScope.getLocalVar(toCheck.assignable.identifier), rExpression.getType())) { + var variable = currentScope.getLocalVar(toCheck.assignable.identifier); + if(variable == null){ + variable = currentFields.get(toCheck.assignable.identifier); + } + + if (!Objects.equals(variable, rExpression.getType())) { errors.add(new TypeMismatchException( "Mismatch types in Assign-Statement: cannot convert from \"" + lResult.getType() + "\" to \"" + rResult.getType() + "\"")); @@ -273,8 +283,8 @@ public class SemanticAnalyzer implements SemanticVisitor { } @Override - public TypeCheckResult analyze(DecrementNode toCheck) { - return null; + public TypeCheckResult analyze(DecrementNode decrementNode) { + return decrementNode.assignableExpression.accept(this); } @Override @@ -284,6 +294,27 @@ public class SemanticAnalyzer implements SemanticVisitor { @Override public TypeCheckResult analyze(MethodCallNode toCheck) { + + var targetType = currentScope.getLocalVar(toCheck.target.identifier); + if(targetType == null){ + targetType = currentFields.get(toCheck.target.identifier); + } + if(targetType instanceof ReferenceType reference){ + var classContext = context.getClass(reference.getIdentifier()); + + if(classContext == null){ + errors.add(new NotDefinedException(toCheck.target.identifier + "is not Defined")); + }else { + var methods = classContext.getMethods(); + for (var method : methods) { + if(toCheck.identifier.equals(method.getIdentifier()) && method.getParameters().size() == toCheck.parameters.size()){ + return new TypeCheckResult(true, method.getType()); + } + } + } + } else { + + } return null; } @@ -316,12 +347,17 @@ public class SemanticAnalyzer implements SemanticVisitor { @Override public TypeCheckResult analyze(NewDeclarationNode toCheck) { + + if(context.containsClass(toCheck.identifier)) { + return new TypeCheckResult(true, new ReferenceType(toCheck.identifier)); + } + return null; } @Override public TypeCheckResult analyze(IncrementNode toCheck) { - return null; + return toCheck.assignableExpression.accept(this); } @Override @@ -357,13 +393,17 @@ public class SemanticAnalyzer implements SemanticVisitor { var valid = true; if (currentScope.contains(unary.identifier)) { - return new TypeCheckResult(valid, currentScope.getLocalVar(unary.identifier)); - } else if(currentFields.get(unary.identifier) != null) { - return new TypeCheckResult(valid, currentFields.get(unary.identifier)); + return new TypeCheckResult(valid, currentScope.getLocalVar(unary.identifier)); + } else if (currentFields.get(unary.identifier) != null) { + return new TypeCheckResult(valid, currentFields.get(unary.identifier)); + } else if (unary.statement != null) { + var result = unary.statement.accept(this); + unary.setType(result.getType()); + return result; } else { errors.add(new NotDeclearedException("Var is not Decleared")); } return new TypeCheckResult(valid, null); - } +} } \ No newline at end of file diff --git a/src/main/java/semantic/context/ClassContext.java b/src/main/java/semantic/context/ClassContext.java index 1a79fc4..b9e39a4 100644 --- a/src/main/java/semantic/context/ClassContext.java +++ b/src/main/java/semantic/context/ClassContext.java @@ -2,11 +2,15 @@ package semantic.context; import ast.ClassNode; import ast.members.FieldNode; +import ast.members.MethodNode; + +import java.util.ArrayList; import java.util.HashMap; public class ClassContext { private HashMap fields; + private ArrayList methods = new ArrayList<>(); public ClassContext(ClassNode classNode) { @@ -15,6 +19,8 @@ public class ClassContext { classNode.members.forEach(member -> { if(member instanceof FieldNode fieldNode) { fields.put(fieldNode.identifier, new FieldContext(fieldNode)); + }else if(member instanceof MethodNode methodNode) { + methods.add(methodNode); } }); @@ -24,4 +30,8 @@ public class ClassContext { return fields.get(name); } + public ArrayList getMethods() { + return methods; + } + } diff --git a/src/main/java/semantic/context/Context.java b/src/main/java/semantic/context/Context.java index d6431ef..39e279a 100644 --- a/src/main/java/semantic/context/Context.java +++ b/src/main/java/semantic/context/Context.java @@ -21,4 +21,8 @@ public class Context { return classes.get(identifier); } + public boolean containsClass(String identifier) { + return classes.containsKey(identifier); + } + } diff --git a/src/main/java/semantic/exeptions/NotDefinedException.java b/src/main/java/semantic/exeptions/NotDefinedException.java new file mode 100644 index 0000000..c374ce0 --- /dev/null +++ b/src/main/java/semantic/exeptions/NotDefinedException.java @@ -0,0 +1,9 @@ +package semantic.exeptions; + +public class NotDefinedException extends RuntimeException { + + public NotDefinedException(String message) { + super(message); + } + +} diff --git a/src/test/java/semantic/EndToTAST.java b/src/test/java/semantic/EndToTAST.java index 3189802..e5fa138 100644 --- a/src/test/java/semantic/EndToTAST.java +++ b/src/test/java/semantic/EndToTAST.java @@ -50,7 +50,7 @@ public class EndToTAST { ASTNode tast = SemanticAnalyzer.generateTast(abstractSyntaxTree); - assertEquals(SemanticAnalyzer.errors.size(), 0); + assertEquals(0, SemanticAnalyzer.errors.size()); assertNotNull(tast); } @@ -255,28 +255,4 @@ public class EndToTAST { } - @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/resources/semantic/endToTAST/CorrectTest.java b/src/test/resources/semantic/endToTAST/CorrectTest.java index 1efa68d..957dc26 100644 --- a/src/test/resources/semantic/endToTAST/CorrectTest.java +++ b/src/test/resources/semantic/endToTAST/CorrectTest.java @@ -2,10 +2,41 @@ public class Example { public int a; - public static int testMethod(int b, boolean bo){ + public Car c; + + public void test(){ + c = new Car(); + int speed = c.getSpeed(); + } + + public static int testReturnMethod(int b, boolean bo){ a = b; return a; + } + public void testOjektMethod(int testInt){ + Test testClass = new Test(); + int b = testClass.getFirstInt(testInt); + } + +} + +public class Test { + + public int firstInt; + + public int getFirstInt(int b){ + return firstInt--; + } + +} + +public class Car{ + + private int speed; + + public int getSpeed(){ + return speed; } } \ No newline at end of file diff --git a/src/test/resources/semantic/endToTAST/WrongIfClause.java b/src/test/resources/semantic/endToTAST/WrongIfClause.java deleted file mode 100644 index f73f052..0000000 --- a/src/test/resources/semantic/endToTAST/WrongIfClause.java +++ /dev/null @@ -1,7 +0,0 @@ -public class Example { - - public static void testMethod(int x){ - - } - -} From 10eb17497eab802a34ff1fdf2930439b9f85736c Mon Sep 17 00:00:00 2001 From: Bruder John Date: Thu, 27 Jun 2024 10:45:38 +0200 Subject: [PATCH 04/11] added some Semantic Tests --- .../unaryexpressions/MemberAccessNode.java | 10 +- .../TargetNode.java | 12 +- src/main/java/semantic/SemanticAnalyzer.java | 108 ++++++++++++++---- src/main/java/semantic/SemanticVisitor.java | 8 +- .../exceptions/NotVisibleException.java | 9 ++ src/test/java/semantic/EndToTypedAstTest.java | 67 +++++++---- .../featureTests/BooleanOperations.class | Bin 0 -> 686 bytes .../input/featureTests/CharManipulation.class | Bin 0 -> 638 bytes .../featureTests/ConditionalStatements.class | Bin 0 -> 780 bytes .../featureTests/EmptyClassExample.class | Bin 0 -> 208 bytes .../input/featureTests/LoopExamples.class | Bin 0 -> 1004 bytes .../featureTests/MethodOverloading.class | Bin 0 -> 1083 bytes .../MethodNotVisible.java | 21 ++++ .../WrongIfClause.java | 8 -- .../CallMethodFromObjekt.java | 20 ++++ .../typedAstFeaturesTests/CorrectTest.java | 35 +----- .../typedAstFeaturesTests/ThisDotMethod.java | 13 +++ 17 files changed, 220 insertions(+), 91 deletions(-) create mode 100644 src/main/java/semantic/exceptions/NotVisibleException.java create mode 100644 src/test/resources/input/featureTests/BooleanOperations.class create mode 100644 src/test/resources/input/featureTests/CharManipulation.class create mode 100644 src/test/resources/input/featureTests/ConditionalStatements.class create mode 100644 src/test/resources/input/featureTests/EmptyClassExample.class create mode 100644 src/test/resources/input/featureTests/LoopExamples.class create mode 100644 src/test/resources/input/featureTests/MethodOverloading.class create mode 100644 src/test/resources/input/typedAstExceptionsTests/MethodNotVisible.java delete mode 100644 src/test/resources/input/typedAstExceptionsTests/WrongIfClause.java create mode 100644 src/test/resources/input/typedAstFeaturesTests/CallMethodFromObjekt.java create mode 100644 src/test/resources/input/typedAstFeaturesTests/ThisDotMethod.java diff --git a/src/main/java/ast/expressions/unaryexpressions/MemberAccessNode.java b/src/main/java/ast/expressions/unaryexpressions/MemberAccessNode.java index aa85286..e171f79 100644 --- a/src/main/java/ast/expressions/unaryexpressions/MemberAccessNode.java +++ b/src/main/java/ast/expressions/unaryexpressions/MemberAccessNode.java @@ -1,11 +1,14 @@ package ast.expressions.unaryexpressions; import ast.ASTNode; +import semantic.SemanticVisitor; +import typechecker.TypeCheckResult; +import visitor.Visitable; import java.util.ArrayList; import java.util.List; -public class MemberAccessNode implements ASTNode { +public class MemberAccessNode implements ASTNode, Visitable { public Boolean thisExpr; public List identifiers = new ArrayList<>(); @@ -17,4 +20,9 @@ public class MemberAccessNode implements ASTNode { identifiers.add(identifier); } + @Override + public TypeCheckResult accept(SemanticVisitor visitor) { + return visitor.analyze(this); + } + } diff --git a/src/main/java/ast/statementexpressions/methodcallstatementnexpressions/TargetNode.java b/src/main/java/ast/statementexpressions/methodcallstatementnexpressions/TargetNode.java index 01e2344..01a1d78 100644 --- a/src/main/java/ast/statementexpressions/methodcallstatementnexpressions/TargetNode.java +++ b/src/main/java/ast/statementexpressions/methodcallstatementnexpressions/TargetNode.java @@ -3,8 +3,11 @@ package ast.statementexpressions.methodcallstatementnexpressions; import ast.ASTNode; import ast.expressions.unaryexpressions.MemberAccessNode; import ast.statementexpressions.NewDeclarationNode; +import semantic.SemanticVisitor; +import typechecker.TypeCheckResult; +import visitor.Visitable; -public class TargetNode implements ASTNode { +public class TargetNode implements ASTNode, Visitable { public Boolean thisTar; public MemberAccessNode memberAccess; public NewDeclarationNode newDeclaration; @@ -25,4 +28,11 @@ public class TargetNode implements ASTNode { public TargetNode(String identifier) { this.identifier = identifier; } + + @Override + public TypeCheckResult accept(SemanticVisitor visitor) { + return visitor.analyze(this); + } + + } \ No newline at end of file diff --git a/src/main/java/semantic/SemanticAnalyzer.java b/src/main/java/semantic/SemanticAnalyzer.java index 6bdd578..2e7e496 100644 --- a/src/main/java/semantic/SemanticAnalyzer.java +++ b/src/main/java/semantic/SemanticAnalyzer.java @@ -9,6 +9,7 @@ import java.util.Objects; import ast.*; import ast.expressions.IExpressionNode; import ast.expressions.binaryexpressions.*; +import ast.expressions.unaryexpressions.MemberAccessNode; import ast.expressions.unaryexpressions.UnaryNode; import ast.members.ConstructorNode; import ast.members.FieldNode; @@ -21,7 +22,9 @@ import ast.statementexpressions.NewDeclarationNode; import ast.statementexpressions.crementexpressions.DecrementNode; import ast.statementexpressions.crementexpressions.IncrementNode; import ast.statementexpressions.methodcallstatementnexpressions.MethodCallNode; +import ast.statementexpressions.methodcallstatementnexpressions.TargetNode; import ast.statements.*; +import ast.type.EnumAccessModifierNode; import ast.type.type.*; import semantic.context.Context; import semantic.exceptions.*; @@ -150,7 +153,7 @@ public class SemanticAnalyzer implements SemanticVisitor { if (resultType == null) { resultType = new BaseType(TypeEnum.VOID); } - if(methodNode.getType() == null){ + if (methodNode.getType() == null) { methodNode.setType(new BaseType(TypeEnum.VOID)); } if (!resultType.equals(methodNode.getType())) { @@ -185,7 +188,7 @@ public class SemanticAnalyzer implements SemanticVisitor { if (toCheck.expression != null) { var result = toCheck.expression.accept(this); return new TypeCheckResult(true, result.getType()); - } else if(toCheck.voidReturn){ + } else if (toCheck.voidReturn) { return new TypeCheckResult(false, new BaseType(TypeEnum.VOID)); } return new TypeCheckResult(true, null); @@ -223,7 +226,7 @@ public class SemanticAnalyzer implements SemanticVisitor { @Override public TypeCheckResult analyze(AssignableNode toCheck) { - if ( currentFields.get(toCheck.identifier) != null){ + if (currentFields.get(toCheck.identifier) != null) { return new TypeCheckResult(true, currentFields.get(toCheck.identifier)); } else if (currentScope.getLocalVar(toCheck.identifier) != null) { return new TypeCheckResult(true, currentScope.getLocalVar(toCheck.identifier)); @@ -264,19 +267,16 @@ public class SemanticAnalyzer implements SemanticVisitor { var rResult = rExpression.accept(this); var variable = currentScope.getLocalVar(toCheck.assignable.identifier); - if(variable == null){ + if (variable == null) { variable = currentFields.get(toCheck.assignable.identifier); } - if (!Objects.equals(variable, rExpression.getType())) { + if (!Objects.equals(variable, rResult.getType())) { errors.add(new TypeMismatchException( "Mismatch types in Assign-Statement: cannot convert from \"" + lResult.getType() + "\" to \"" + rResult.getType() + "\"")); valid = false; } -// else { -// toCheck.setType(assignable.getType()); -// } valid = valid && lResult.isValid() && rResult.isValid(); currentNullType = null; return new TypeCheckResult(valid, null); // return type is null to get the return type sufficently @@ -295,25 +295,43 @@ public class SemanticAnalyzer implements SemanticVisitor { @Override public TypeCheckResult analyze(MethodCallNode toCheck) { - var targetType = currentScope.getLocalVar(toCheck.target.identifier); - if(targetType == null){ - targetType = currentFields.get(toCheck.target.identifier); + if (toCheck.target.identifier != null) { + var targetType = currentScope.getLocalVar(toCheck.target.identifier); + if (targetType == null) { + targetType = currentFields.get(toCheck.target.identifier); + } + if (targetType instanceof ReferenceType reference) { + return new TypeCheckResult(true, getTypeFromMethod(toCheck, reference)); + } + } else { + if(toCheck.target.thisTar){ + return new TypeCheckResult(true, getTypeFromMethod(toCheck, new ReferenceType(currentClass.identifier))); + } else { + var result = toCheck.target.accept(this); + if (result.getType() instanceof ReferenceType reference) { + return new TypeCheckResult(true, getTypeFromMethod(toCheck, reference)); + } + } } - if(targetType instanceof ReferenceType reference){ - var classContext = context.getClass(reference.getIdentifier()); + return null; + } - if(classContext == null){ - errors.add(new NotDefinedException(toCheck.target.identifier + "is not Defined")); - }else { - var methods = classContext.getMethods(); - for (var method : methods) { - if(toCheck.identifier.equals(method.getIdentifier()) && method.getParameters().size() == toCheck.parameters.size()){ - return new TypeCheckResult(true, method.getType()); + private ITypeNode getTypeFromMethod(MethodCallNode toCheck, ReferenceType reference) { + var classContext = context.getClass(reference.getIdentifier()); + + if (classContext == null) { + errors.add(new NotDeclaredException(toCheck.target.identifier + "is not Defined")); + } else { + var methods = classContext.getMethods(); + for (var method : methods) { + if (toCheck.identifier.equals(method.getIdentifier()) && method.getParameters().size() == toCheck.parameters.size()) { + if(method.accesModifier.accessType == EnumAccessModifierNode.PUBLIC){ + return method.getType(); + }else { + errors.add(new NotVisibleException("This Method is not Visible")); } } } - } else { - } return null; } @@ -348,7 +366,7 @@ public class SemanticAnalyzer implements SemanticVisitor { @Override public TypeCheckResult analyze(NewDeclarationNode toCheck) { - if(context.containsClass(toCheck.identifier)) { + if (context.containsClass(toCheck.identifier)) { return new TypeCheckResult(true, new ReferenceType(toCheck.identifier)); } @@ -404,6 +422,48 @@ public class SemanticAnalyzer implements SemanticVisitor { errors.add(new NotDeclaredException("Var is not Declared")); } return new TypeCheckResult(valid, null); -} + } + + @Override + public TypeCheckResult analyze(MemberAccessNode memberAccessNode) { + + ITypeNode currentType = null; + + for (String s : memberAccessNode.identifiers) { + if (currentType == null) { + if (currentScope.getLocalVar(s) != null) { + currentType = currentScope.getLocalVar(s); + + } else if (currentFields.get(s) != null) { + currentType = currentFields.get(s); + } else { + errors.add(new NotDeclaredException(s + "Not Declared")); + return new TypeCheckResult(false, null); + } + + } else { + if(currentType instanceof ReferenceType reference) { + var currentTypeClass = context.getClass(reference.getIdentifier()); + + var currentField = currentTypeClass.getField(s); + currentType = currentField.getType(); + } + } + + } + + return new TypeCheckResult(true, currentType); + } + + @Override + public TypeCheckResult analyze(TargetNode targetNode) { + + if (targetNode.memberAccess != null) { + return targetNode.memberAccess.accept(this); + } + return null; + } + + } \ No newline at end of file diff --git a/src/main/java/semantic/SemanticVisitor.java b/src/main/java/semantic/SemanticVisitor.java index 974d1de..87ba85a 100644 --- a/src/main/java/semantic/SemanticVisitor.java +++ b/src/main/java/semantic/SemanticVisitor.java @@ -2,6 +2,7 @@ package semantic; import ast.*; import ast.expressions.binaryexpressions.*; +import ast.expressions.unaryexpressions.MemberAccessNode; import ast.expressions.unaryexpressions.UnaryNode; import ast.members.*; import ast.parameters.ParameterNode; @@ -11,6 +12,7 @@ import ast.statementexpressions.NewDeclarationNode; import ast.statementexpressions.crementexpressions.DecrementNode; import ast.statementexpressions.crementexpressions.IncrementNode; import ast.statementexpressions.methodcallstatementnexpressions.MethodCallNode; +import ast.statementexpressions.methodcallstatementnexpressions.TargetNode; import ast.statements.*; import typechecker.TypeCheckResult; @@ -38,8 +40,6 @@ public interface SemanticVisitor { TypeCheckResult analyze(ElseNode toCheck); - //TypeCheckResult analyze(ForNode toCheck); - TypeCheckResult analyze(AssignNode toCheck); TypeCheckResult analyze(DecrementNode toCheck); @@ -66,4 +66,8 @@ public interface SemanticVisitor { TypeCheckResult analyze(UnaryNode toCheck); + TypeCheckResult analyze(MemberAccessNode toCheck); + + TypeCheckResult analyze(TargetNode toCheck); + } \ No newline at end of file diff --git a/src/main/java/semantic/exceptions/NotVisibleException.java b/src/main/java/semantic/exceptions/NotVisibleException.java new file mode 100644 index 0000000..efd7444 --- /dev/null +++ b/src/main/java/semantic/exceptions/NotVisibleException.java @@ -0,0 +1,9 @@ +package semantic.exceptions; + +public class NotVisibleException extends RuntimeException { + + public NotVisibleException(String message) { + super(message); + } + +} diff --git a/src/test/java/semantic/EndToTypedAstTest.java b/src/test/java/semantic/EndToTypedAstTest.java index 9bf5485..7d13f07 100644 --- a/src/test/java/semantic/EndToTypedAstTest.java +++ b/src/test/java/semantic/EndToTypedAstTest.java @@ -26,11 +26,37 @@ 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 testOnlyOneFile() { + SemanticAnalyzer.clearAnalyzer(); + + CharStream codeCharStream = null; + try { + codeCharStream = CharStreams.fromPath(Paths.get("src/test/resources/input/typedAstFeaturesTests/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); + + var result = SemanticAnalyzer.generateTast(abstractSyntaxTree); + + assertTrue(SemanticAnalyzer.errors.isEmpty()); + } + @Test public void exceptionsTest() { String directoryPath = "src/test/resources/input/typedAstExceptionsTests"; @@ -88,7 +114,7 @@ public class EndToTypedAstTest { } @Test - public void featureTest(){ + public void featureTest() { String directoryPath = "src/test/resources/input/typedAstFeaturesTests"; File folder = new File(directoryPath); if (folder.isDirectory()) { @@ -127,9 +153,8 @@ public class EndToTypedAstTest { } - - // ------------------ 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. @@ -158,25 +183,25 @@ public class EndToTypedAstTest { } /** - * 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); + * 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; } - return exceptionClass; -} /** * This method is used to load custom exceptions from a specified package. diff --git a/src/test/resources/input/featureTests/BooleanOperations.class b/src/test/resources/input/featureTests/BooleanOperations.class new file mode 100644 index 0000000000000000000000000000000000000000..cd8092afc9340340c3c834d5302392425b071189 GIT binary patch literal 686 zcmZuv(P|Sx6g{)qWRi8$CQXy7wQ5^!lNHPdRD7sVL828R1>2`d9G7V~vthF-^jG`= zUwl!t1qDCAk5bR1!6M4A_s+d@?>XmQ_Q%h!-vR8R6Tm}3!VghINuYMDPE|KiHty~Z zj`c7XC_OUPrS&$@Pd7>6DDk-b{r_yDu|i^M0ObHQI4-DuN z=bfvf-Cz{))x8JN1w^#^1@a>!flb;46li^(A}S~`%bm>o*61B(G5QSo;ZKVz0*i$k zoYql1C4tMokpHO>nj@CJD(%rd=uI6cR4$2_T5*j=!D3<6--2f20OR zpzu-0+I$koHJXPWitt?c0p<~q-Z_@(fsFM@7D=O%nDj^)qf!CU@kuUO;Y9(b(XrJp zu;ii=U>Vha%zEdiMvdu_WVEbyAKTDL`&+7G(=(}(<6SHFGQbL633x+gx>F)8Z+-)8T_`M`c2kNu7Xt;kUWf-h%BbokHN5H}fx%-Xyk-a>?H zH*hZ*32YHd$Ppbrd3Y#rl|z`;t@CR&^Winzi>DGx0?EQ|lV~kArxt~0^7ak@3luN0 zqK@q;|A4kOv;7OjALYGUEOf6>ZcR{|V6|1=pI~Da&$_Kq2s~*YOFZWaR*7{~Df*u4 HbJ+OR=|(Sh3MEvQIh;9X&i6ZWW`F(p{u96})RKrGYQu67LtG$pPh>=!bG3bvR~?o($S@Bp^-` zNMqSX#>EP0?)XZ~=$w+6mq zn``B(MSTh+o55t%k*}30E-jq=kr@GY*h_@ZE4cVfv{Cx(mG(JzRc1{-S$%-0ZhV9N znLB|!+BDAs7QYx0h%?G7&Fi|XGMb0gudqKN{RK3hnG-MBjm1>u2b@di0Z$sn$^52wX1pk! m^MiXlt#KW4{kzCEIY5qbtF(D+q5u!;Bo+xM5m045f`h-jQ=H!b literal 0 HcmV?d00001 diff --git a/src/test/resources/input/featureTests/EmptyClassExample.class b/src/test/resources/input/featureTests/EmptyClassExample.class new file mode 100644 index 0000000000000000000000000000000000000000..a6a129d83eb7b7fa699093038b18c5956b9ac7cc GIT binary patch literal 208 zcmX^0Z`VEs1_mbvUM>bE24;2!79Ivx1~x_pfvm)`ME#t^ymWp4q^#8B5=I6#o6Nk- z5<5l)W)00Sb_Nbc20_={f|5$-oW$Z{*NVj4f}B)F1{UZ16d=X#lbM(5SDKrYS`?C) z1d`wi&Mz%WPIb!!al|lm>VYg|P-I{Sx&s6lfe`2tAjt{j$%6R|46It)85lQ$rMZA4 ONE)J)8%Q%T@BjcvAt~Pg literal 0 HcmV?d00001 diff --git a/src/test/resources/input/featureTests/LoopExamples.class b/src/test/resources/input/featureTests/LoopExamples.class new file mode 100644 index 0000000000000000000000000000000000000000..2a398c6e58dba159bd89b9357647b2657cb08f32 GIT binary patch literal 1004 zcmaJ=L2nX46#fP%3+onI5GtY-D^;jkwBDrgP$IEOt0pwvpX~rul@+n zUOekTlOFs5{uY0MY1FqsA_U?dW@h(&?|a|-=IxK)7vBNwVaG%SQ3EjxONcY9obhvB zbGSUMy=tF{j%JAO+S1m~7^0QxaS{n64VV_Lz?y-#hJh9?q11qqat9+KTh(6sw$v@{ z3+~o4R5N8EjTMG9m-j_O$qv^iw(ij>&|K<(ax44Qar#IH<=XPJZX$!MfvXmB$TMUY z@G}@*Sj~|k$vj2%I0J^1fdYedpp^IgEq6UfP|a9Fbp=EEz?S0Wz-LiRtaF^t5jMg$`f;bo+ JqK3yP`~|8~{Zs$| literal 0 HcmV?d00001 diff --git a/src/test/resources/input/featureTests/MethodOverloading.class b/src/test/resources/input/featureTests/MethodOverloading.class new file mode 100644 index 0000000000000000000000000000000000000000..2357744da74e54140524878508a87dd6fe8f3e92 GIT binary patch literal 1083 zcmaJ=T~8B16g@+?-L@>>0wM)g1#M}i0)E%{Koeq89(PmmwPA0 zgZi0hD2Bvq$8*#hhFCUtY$C}p^G>K!**rKGzAJgt@lMh(5ldklmWc@qlbE_eRqF*x zw247>iEzFeHgRO}(04plQ@-HslBSrkFpD|D@n(}Do~=}Jm08j`Z(#w842x~v5@qQ% zxccCzQ(6UzdnzE#Y$X@bhT4gfR1xPA?wDA%kiiPW+=#vmW=E@VJxwx9kvrDH*0eC2 zydX)TCIT}UW!V%AQ&q!@A;qEmu79#CFa+Qz< zArgdK8N!-KVI3QN>>-KK!U{iOe!N7g`UB~FJaK{PE8GGua9bA)U0J=NF?8ix=WN(# q97$O8I3|#%#~Q-};v2(5WGPS5>JjzIg)xs^s-@}s37+8vmi_{y1Na&M literal 0 HcmV?d00001 diff --git a/src/test/resources/input/typedAstExceptionsTests/MethodNotVisible.java b/src/test/resources/input/typedAstExceptionsTests/MethodNotVisible.java new file mode 100644 index 0000000..2631c3e --- /dev/null +++ b/src/test/resources/input/typedAstExceptionsTests/MethodNotVisible.java @@ -0,0 +1,21 @@ +// @expected: NotVisibleException +public class Test { + + public int firstInt; + public Car ca; + + public int speed(){ + return ca.getSpeed(); + } + +} + +public class Car{ + + private int speed; + + private int getSpeed(){ + return speed; + } + +} \ No newline at end of file diff --git a/src/test/resources/input/typedAstExceptionsTests/WrongIfClause.java b/src/test/resources/input/typedAstExceptionsTests/WrongIfClause.java deleted file mode 100644 index e1b7c27..0000000 --- a/src/test/resources/input/typedAstExceptionsTests/WrongIfClause.java +++ /dev/null @@ -1,8 +0,0 @@ -// @expected: TypeMismatchException -public class Example { - - public static void testMethod(int x){ - - } - -} diff --git a/src/test/resources/input/typedAstFeaturesTests/CallMethodFromObjekt.java b/src/test/resources/input/typedAstFeaturesTests/CallMethodFromObjekt.java new file mode 100644 index 0000000..61b94f2 --- /dev/null +++ b/src/test/resources/input/typedAstFeaturesTests/CallMethodFromObjekt.java @@ -0,0 +1,20 @@ +public class Test { + + public int firstInt; + public Car ca; + + public int speed(){ + return ca.getSpeed(); + } + +} + +public class Car{ + + private int speed; + + public int getSpeed(){ + return speed; + } + +} \ No newline at end of file diff --git a/src/test/resources/input/typedAstFeaturesTests/CorrectTest.java b/src/test/resources/input/typedAstFeaturesTests/CorrectTest.java index 957dc26..1f51430 100644 --- a/src/test/resources/input/typedAstFeaturesTests/CorrectTest.java +++ b/src/test/resources/input/typedAstFeaturesTests/CorrectTest.java @@ -1,41 +1,8 @@ -public class Example { - - public int a; - - public Car c; - - public void test(){ - c = new Car(); - int speed = c.getSpeed(); - } - - public static int testReturnMethod(int b, boolean bo){ - a = b; - return a; - } - - public void testOjektMethod(int testInt){ - Test testClass = new Test(); - int b = testClass.getFirstInt(testInt); - } - -} - -public class Test { - - public int firstInt; - - public int getFirstInt(int b){ - return firstInt--; - } - -} - public class Car{ private int speed; - public int getSpeed(){ + public int getSpeed(boolean boo){ return speed; } diff --git a/src/test/resources/input/typedAstFeaturesTests/ThisDotMethod.java b/src/test/resources/input/typedAstFeaturesTests/ThisDotMethod.java new file mode 100644 index 0000000..36bcade --- /dev/null +++ b/src/test/resources/input/typedAstFeaturesTests/ThisDotMethod.java @@ -0,0 +1,13 @@ +public class Car{ + + private int speed; + + public int getSpeed(){ + return speed; + } + + public int test(){ + return this.getSpeed(); + } + +} \ No newline at end of file From a34c7ded50cebdeb290c93f0d78053bbd58581e1 Mon Sep 17 00:00:00 2001 From: Bruder John Date: Thu, 27 Jun 2024 15:04:01 +0200 Subject: [PATCH 05/11] added Some Semantic Checks --- src/main/java/ast/members/MethodNode.java | 2 +- src/main/java/ast/statements/ElseNode.java | 4 +- src/main/java/ast/statements/IfElseNode.java | 8 +- src/main/java/ast/statements/IfNode.java | 6 +- src/main/java/ast/type/ValueNode.java | 11 +- src/main/java/semantic/SemanticAnalyzer.java | 153 +++++++++++++----- src/main/java/semantic/SemanticVisitor.java | 3 + .../semantic/exceptions/WrongOverloading.java | 9 ++ src/test/java/semantic/EndToTypedAstTest.java | 3 + src/test/java/semantic/SemanticTest.java | 12 ++ .../IfExpressionInt.java | 14 ++ .../MissingOverloadingParameter.java | 19 +++ .../MultipleReturnTypes.java | 2 +- .../CorrectMethodParameter.java | 18 +++ .../typedAstFeaturesTests/CorrectTest.java | 20 ++- .../IfExpressionBoolean.java | 13 ++ .../input/typedAstFeaturesTests/IfReturn.java | 13 ++ .../VoidReturnTypeIF.java | 13 ++ 18 files changed, 267 insertions(+), 56 deletions(-) create mode 100644 src/main/java/semantic/exceptions/WrongOverloading.java create mode 100644 src/test/resources/input/typedAstExceptionsTests/IfExpressionInt.java create mode 100644 src/test/resources/input/typedAstExceptionsTests/MissingOverloadingParameter.java create mode 100644 src/test/resources/input/typedAstFeaturesTests/CorrectMethodParameter.java create mode 100644 src/test/resources/input/typedAstFeaturesTests/IfExpressionBoolean.java create mode 100644 src/test/resources/input/typedAstFeaturesTests/IfReturn.java create mode 100644 src/test/resources/input/typedAstFeaturesTests/VoidReturnTypeIF.java diff --git a/src/main/java/ast/members/MethodNode.java b/src/main/java/ast/members/MethodNode.java index 5e10d48..1345508 100644 --- a/src/main/java/ast/members/MethodNode.java +++ b/src/main/java/ast/members/MethodNode.java @@ -46,7 +46,7 @@ public class MethodNode implements MemberNode, Visitable { } for (int i = 0; i < this.getParameters().size(); i++) { - if (this.getParameters().get(i).type.equals(methodNode.getParameters().get(i).type)) { + if (!this.getParameters().get(i).type.equals(methodNode.getParameters().get(i).type)) { return false; } } diff --git a/src/main/java/ast/statements/ElseNode.java b/src/main/java/ast/statements/ElseNode.java index 78b62f1..7099895 100644 --- a/src/main/java/ast/statements/ElseNode.java +++ b/src/main/java/ast/statements/ElseNode.java @@ -5,7 +5,7 @@ import semantic.SemanticVisitor; import typechecker.TypeCheckResult; public class ElseNode implements IStatementNode { - BlockNode block; + public BlockNode block; public ElseNode(BlockNode block) { this.block = block; @@ -14,6 +14,6 @@ public class ElseNode implements IStatementNode { @Override public TypeCheckResult accept(SemanticVisitor visitor) { - return null; + return visitor.analyze(this); } } diff --git a/src/main/java/ast/statements/IfElseNode.java b/src/main/java/ast/statements/IfElseNode.java index 34d40f3..55d4191 100644 --- a/src/main/java/ast/statements/IfElseNode.java +++ b/src/main/java/ast/statements/IfElseNode.java @@ -8,9 +8,9 @@ import java.util.ArrayList; import java.util.List; public class IfElseNode implements IStatementNode { - IfNode ifStatement; - List elseIfStatements = new ArrayList<>(); - ElseNode elseStatement; + public IfNode ifStatement; + public List elseIfStatements = new ArrayList<>(); + public ElseNode elseStatement; public IfElseNode(IfNode ifStatement, ElseNode elseNode) { this.ifStatement = ifStatement; @@ -23,6 +23,6 @@ public class IfElseNode implements IStatementNode { @Override public TypeCheckResult accept(SemanticVisitor visitor) { - return null; + return visitor.analyze(this); } } diff --git a/src/main/java/ast/statements/IfNode.java b/src/main/java/ast/statements/IfNode.java index 2f30788..46e15c0 100644 --- a/src/main/java/ast/statements/IfNode.java +++ b/src/main/java/ast/statements/IfNode.java @@ -6,8 +6,8 @@ import semantic.SemanticVisitor; import typechecker.TypeCheckResult; public class IfNode implements IStatementNode { - IExpressionNode expression; - BlockNode block; + public IExpressionNode expression; + public BlockNode block; public IfNode(IExpressionNode expression, BlockNode block) { this.expression = expression; @@ -16,6 +16,6 @@ public class IfNode implements IStatementNode { @Override public TypeCheckResult accept(SemanticVisitor visitor) { - return null; + return visitor.analyze(this); } } diff --git a/src/main/java/ast/type/ValueNode.java b/src/main/java/ast/type/ValueNode.java index b51f799..ec35af0 100644 --- a/src/main/java/ast/type/ValueNode.java +++ b/src/main/java/ast/type/ValueNode.java @@ -1,8 +1,11 @@ package ast.type; import ast.ASTNode; +import semantic.SemanticVisitor; +import typechecker.TypeCheckResult; +import visitor.Visitable; -public class ValueNode implements ASTNode { +public class ValueNode implements ASTNode, Visitable { public EnumValueNode valueType; public String value; @@ -10,4 +13,10 @@ public class ValueNode implements ASTNode { this.valueType = valueType; this.value = value; } + + + @Override + public TypeCheckResult accept(SemanticVisitor visitor) { + return visitor.analyze(this); + } } diff --git a/src/main/java/semantic/SemanticAnalyzer.java b/src/main/java/semantic/SemanticAnalyzer.java index 2e7e496..1f318f2 100644 --- a/src/main/java/semantic/SemanticAnalyzer.java +++ b/src/main/java/semantic/SemanticAnalyzer.java @@ -25,7 +25,9 @@ import ast.statementexpressions.methodcallstatementnexpressions.MethodCallNode; import ast.statementexpressions.methodcallstatementnexpressions.TargetNode; import ast.statements.*; import ast.type.EnumAccessModifierNode; +import ast.type.ValueNode; import ast.type.type.*; +import com.sun.jdi.IntegerType; import semantic.context.Context; import semantic.exceptions.*; import typechecker.TypeCheckResult; @@ -156,11 +158,6 @@ public class SemanticAnalyzer implements SemanticVisitor { if (methodNode.getType() == null) { methodNode.setType(new BaseType(TypeEnum.VOID)); } - if (!resultType.equals(methodNode.getType())) { - errors.add(new TypeMismatchException("Method-Declaration " + methodNode.getIdentifier() + " with type " - + methodNode.getType() + " has at least one Mismatching return Type:")); - valid = false; - } return new TypeCheckResult(valid, resultType); @@ -180,6 +177,16 @@ public class SemanticAnalyzer implements SemanticVisitor { @Override public TypeCheckResult analyze(IfNode toCheck) { + toCheck.block.accept(this); + + var resultExpression = toCheck.expression.accept(this); + if(resultExpression.isValid()){ + if(!resultExpression.getType().equals(new BaseType(TypeEnum.BOOL))){ + errors.add(new TypeMismatchException("Expression must be Boolean")); + return new TypeCheckResult(false, new BaseType(TypeEnum.VOID)); + } + } + return new TypeCheckResult(true, null); } @@ -187,9 +194,14 @@ public class SemanticAnalyzer implements SemanticVisitor { public TypeCheckResult analyze(ReturnNode toCheck) { if (toCheck.expression != null) { var result = toCheck.expression.accept(this); + if(result.isValid()){ + if(!result.getType().equals(currentMethodReturnType)){ + errors.add(new TypeMismatchException("Mismatched return Type from method")); + } + } return new TypeCheckResult(true, result.getType()); } else if (toCheck.voidReturn) { - return new TypeCheckResult(false, new BaseType(TypeEnum.VOID)); + return new TypeCheckResult(true, new BaseType(TypeEnum.VOID)); } return new TypeCheckResult(true, null); @@ -216,7 +228,9 @@ public class SemanticAnalyzer implements SemanticVisitor { if (blockReturnType == null) { blockReturnType = result.getType(); } else { - errors.add(new MultipleReturnTypes("There are multiple Return types")); + if(!blockReturnType.equals(result.getType())) { + errors.add(new MultipleReturnTypes("There are multiple Return types")); + } } } } @@ -238,6 +252,7 @@ public class SemanticAnalyzer implements SemanticVisitor { @Override public TypeCheckResult analyze(ElseNode toCheck) { + toCheck.block.accept(this); return null; } @@ -289,7 +304,11 @@ public class SemanticAnalyzer implements SemanticVisitor { @Override public TypeCheckResult analyze(IfElseNode toCheck) { - return new TypeCheckResult(true, null); + var resultIf = toCheck.ifStatement.accept(this); + + var resultElse = toCheck.elseStatement.accept(this); + + return new TypeCheckResult(true, new BaseType(TypeEnum.VOID)); } @Override @@ -301,11 +320,20 @@ public class SemanticAnalyzer implements SemanticVisitor { targetType = currentFields.get(toCheck.target.identifier); } if (targetType instanceof ReferenceType reference) { - return new TypeCheckResult(true, getTypeFromMethod(toCheck, reference)); + var type = getTypeFromMethod(toCheck, reference); + if(type != null){ + return new TypeCheckResult(true, type); + }else { + return new TypeCheckResult(false, null); + } + } } else { if(toCheck.target.thisTar){ - return new TypeCheckResult(true, getTypeFromMethod(toCheck, new ReferenceType(currentClass.identifier))); + var type = getTypeFromMethod(toCheck, new ReferenceType(currentClass.identifier)); + if(type != null){ + return new TypeCheckResult(true, type); + } } else { var result = toCheck.target.accept(this); if (result.getType() instanceof ReferenceType reference) { @@ -313,27 +341,7 @@ public class SemanticAnalyzer implements SemanticVisitor { } } } - return null; - } - - private ITypeNode getTypeFromMethod(MethodCallNode toCheck, ReferenceType reference) { - var classContext = context.getClass(reference.getIdentifier()); - - if (classContext == null) { - errors.add(new NotDeclaredException(toCheck.target.identifier + "is not Defined")); - } else { - var methods = classContext.getMethods(); - for (var method : methods) { - if (toCheck.identifier.equals(method.getIdentifier()) && method.getParameters().size() == toCheck.parameters.size()) { - if(method.accesModifier.accessType == EnumAccessModifierNode.PUBLIC){ - return method.getType(); - }else { - errors.add(new NotVisibleException("This Method is not Visible")); - } - } - } - } - return null; + return new TypeCheckResult(false, null); } @Override @@ -344,6 +352,9 @@ public class SemanticAnalyzer implements SemanticVisitor { TypeCheckResult result = localVarDecl.expression.accept(this); var resultType = localVarDecl.expression.getType(); + if(result.getType() != null){ + resultType = result.getType(); + } valid = result.isValid() && valid; if (!Objects.equals(resultType, localVarDecl.type)) { @@ -410,17 +421,26 @@ public class SemanticAnalyzer implements SemanticVisitor { public TypeCheckResult analyze(UnaryNode unary) { var valid = true; - if (currentScope.contains(unary.identifier)) { - return new TypeCheckResult(valid, currentScope.getLocalVar(unary.identifier)); - } else if (currentFields.get(unary.identifier) != null) { - return new TypeCheckResult(valid, currentFields.get(unary.identifier)); - } else if (unary.statement != null) { + if(unary.identifier != null){ + if (currentScope.contains(unary.identifier)) { + return new TypeCheckResult(valid, currentScope.getLocalVar(unary.identifier)); + } else if (currentFields.get(unary.identifier) != null) { + return new TypeCheckResult(valid, currentFields.get(unary.identifier)); + } else if (unary.statement != null) { + var result = unary.statement.accept(this); + unary.setType(result.getType()); + return result; + } else { + errors.add(new NotDeclaredException("Var is not Declared")); + } + } else if (unary.statement != null){ var result = unary.statement.accept(this); - unary.setType(result.getType()); - return result; - } else { - errors.add(new NotDeclaredException("Var is not Declared")); + return new TypeCheckResult(result.isValid(), result.getType()); + } else if(unary.value != null){ + var result = unary.value.accept(this); + return new TypeCheckResult(result.isValid(), result.getType()); } + return new TypeCheckResult(valid, null); } @@ -464,6 +484,59 @@ public class SemanticAnalyzer implements SemanticVisitor { return null; } + @Override + public TypeCheckResult analyze(ValueNode valueNode) { + switch (valueNode.valueType){ + case INT_VALUE -> { + return new TypeCheckResult(true, new BaseType(TypeEnum.INT)); + } + case CHAR_VALUE -> { + return new TypeCheckResult(true, new BaseType(TypeEnum.CHAR)); + } + case BOOLEAN_VALUE -> { + return new TypeCheckResult(true, new BaseType(TypeEnum.BOOL)); + } + default -> { + return new TypeCheckResult(false, null); + } + } + } + + private ITypeNode getTypeFromMethod(MethodCallNode toCheck, ReferenceType reference) { + var classContext = context.getClass(reference.getIdentifier()); + + if (classContext == null) { + errors.add(new NotDeclaredException(toCheck.target.identifier + "is not Defined")); + } else { + var methods = classContext.getMethods(); + for (var method : methods) { + if (toCheck.identifier.equals(method.getIdentifier())) { + if(method.getParameters().size() == toCheck.parameters.size() && !(method instanceof ConstructorNode)){ + boolean same = true; + for(int i = 0; i < method.getParameters().size(); i++){ + var result1 = method.getParameters().get(i).accept(this); + var result2 = toCheck.parameters.get(i).accept(this); + if (Objects.equals(result1.getType(), result2.getType())) { + same = false; + } + } + if(same){ + if(method.accesModifier.accessType == EnumAccessModifierNode.PUBLIC){ + if(method.getType() == null){ + return new BaseType(TypeEnum.VOID); + } + return method.getType(); + }else { + errors.add(new NotVisibleException("This Method is not Visible")); + } + } + } + } + } + errors.add(new WrongOverloading("No Method found with this parameters")); + } + return null; + } } \ No newline at end of file diff --git a/src/main/java/semantic/SemanticVisitor.java b/src/main/java/semantic/SemanticVisitor.java index 87ba85a..0c979ca 100644 --- a/src/main/java/semantic/SemanticVisitor.java +++ b/src/main/java/semantic/SemanticVisitor.java @@ -14,6 +14,7 @@ import ast.statementexpressions.crementexpressions.IncrementNode; import ast.statementexpressions.methodcallstatementnexpressions.MethodCallNode; import ast.statementexpressions.methodcallstatementnexpressions.TargetNode; import ast.statements.*; +import ast.type.ValueNode; import typechecker.TypeCheckResult; public interface SemanticVisitor { @@ -70,4 +71,6 @@ public interface SemanticVisitor { TypeCheckResult analyze(TargetNode toCheck); + TypeCheckResult analyze(ValueNode toCheck); + } \ No newline at end of file diff --git a/src/main/java/semantic/exceptions/WrongOverloading.java b/src/main/java/semantic/exceptions/WrongOverloading.java new file mode 100644 index 0000000..5cb42a8 --- /dev/null +++ b/src/main/java/semantic/exceptions/WrongOverloading.java @@ -0,0 +1,9 @@ +package semantic.exceptions; + +public class WrongOverloading extends RuntimeException { + + public WrongOverloading(String message) { + super(message); + } + +} diff --git a/src/test/java/semantic/EndToTypedAstTest.java b/src/test/java/semantic/EndToTypedAstTest.java index 7d13f07..637ebc1 100644 --- a/src/test/java/semantic/EndToTypedAstTest.java +++ b/src/test/java/semantic/EndToTypedAstTest.java @@ -141,6 +141,9 @@ public class EndToTypedAstTest { ASTNode typedAst = SemanticAnalyzer.generateTast(abstractSyntaxTree); System.out.println("Testing the file: " + file.getName()); + for(Exception runtimeException : SemanticAnalyzer.errors){ + runtimeException.printStackTrace(); + } assertTrue(SemanticAnalyzer.errors.isEmpty()); assertNotNull(typedAst); } diff --git a/src/test/java/semantic/SemanticTest.java b/src/test/java/semantic/SemanticTest.java index a4039ac..58d0210 100644 --- a/src/test/java/semantic/SemanticTest.java +++ b/src/test/java/semantic/SemanticTest.java @@ -3,6 +3,18 @@ package semantic; public class SemanticTest { + public void test(){ + + } + + public void test(int a, boolean b){ + + } + + public void test(boolean b, int a){ + + } + // @Test // public void alreadyDeclaredLocalFieldVar() { // ProgramNode programNode = new ProgramNode(); diff --git a/src/test/resources/input/typedAstExceptionsTests/IfExpressionInt.java b/src/test/resources/input/typedAstExceptionsTests/IfExpressionInt.java new file mode 100644 index 0000000..2fbbbfc --- /dev/null +++ b/src/test/resources/input/typedAstExceptionsTests/IfExpressionInt.java @@ -0,0 +1,14 @@ +// @expected: TypeMismatchException +public class Test{ + + public void test(int x){ + + if(x){ + + } else { + + } + + } + +} \ No newline at end of file diff --git a/src/test/resources/input/typedAstExceptionsTests/MissingOverloadingParameter.java b/src/test/resources/input/typedAstExceptionsTests/MissingOverloadingParameter.java new file mode 100644 index 0000000..17eac69 --- /dev/null +++ b/src/test/resources/input/typedAstExceptionsTests/MissingOverloadingParameter.java @@ -0,0 +1,19 @@ +// @expected: WrongOverloading +public class Test{ + + public void test(int x){ + + if(this.get()){ + + } else { + + } + + } + public boolean b; + + public boolean get(int c){ + return b; + } + +} \ No newline at end of file diff --git a/src/test/resources/input/typedAstExceptionsTests/MultipleReturnTypes.java b/src/test/resources/input/typedAstExceptionsTests/MultipleReturnTypes.java index f368e60..b59f6b9 100644 --- a/src/test/resources/input/typedAstExceptionsTests/MultipleReturnTypes.java +++ b/src/test/resources/input/typedAstExceptionsTests/MultipleReturnTypes.java @@ -1,4 +1,4 @@ -// @expected: MultipleReturnTypes +// @expected: TypeMismatchException public class Example { public static int testMethod(int x, char c){ diff --git a/src/test/resources/input/typedAstFeaturesTests/CorrectMethodParameter.java b/src/test/resources/input/typedAstFeaturesTests/CorrectMethodParameter.java new file mode 100644 index 0000000..ecfad3e --- /dev/null +++ b/src/test/resources/input/typedAstFeaturesTests/CorrectMethodParameter.java @@ -0,0 +1,18 @@ +public class Test{ + + public void test(int x){ + + if(this.get(x)){ + + } else { + + } + + } + public boolean b; + + public boolean get(int c){ + return b; + } + +} \ No newline at end of file diff --git a/src/test/resources/input/typedAstFeaturesTests/CorrectTest.java b/src/test/resources/input/typedAstFeaturesTests/CorrectTest.java index 1f51430..e5219be 100644 --- a/src/test/resources/input/typedAstFeaturesTests/CorrectTest.java +++ b/src/test/resources/input/typedAstFeaturesTests/CorrectTest.java @@ -1,9 +1,21 @@ -public class Car{ +public class Test{ - private int speed; + public int i; + public boolean b; - public int getSpeed(boolean boo){ - return speed; + public int test(){ + + return i; + + } + + public void test(int a){ + + } + + public int test(boolean bool){ + int ret = 1; + return ret; } } \ No newline at end of file diff --git a/src/test/resources/input/typedAstFeaturesTests/IfExpressionBoolean.java b/src/test/resources/input/typedAstFeaturesTests/IfExpressionBoolean.java new file mode 100644 index 0000000..526a2f2 --- /dev/null +++ b/src/test/resources/input/typedAstFeaturesTests/IfExpressionBoolean.java @@ -0,0 +1,13 @@ +public class Car{ + + public void test(boolean boo){ + + if(boo){ + + } else { + + } + + } + +} \ No newline at end of file diff --git a/src/test/resources/input/typedAstFeaturesTests/IfReturn.java b/src/test/resources/input/typedAstFeaturesTests/IfReturn.java new file mode 100644 index 0000000..00cd263 --- /dev/null +++ b/src/test/resources/input/typedAstFeaturesTests/IfReturn.java @@ -0,0 +1,13 @@ +public class Car{ + + public int getSpeed(boolean bool, int a, int b){ + + if(bool){ + return a; + } else { + return b; + } + + } + +} \ No newline at end of file diff --git a/src/test/resources/input/typedAstFeaturesTests/VoidReturnTypeIF.java b/src/test/resources/input/typedAstFeaturesTests/VoidReturnTypeIF.java new file mode 100644 index 0000000..bc31a27 --- /dev/null +++ b/src/test/resources/input/typedAstFeaturesTests/VoidReturnTypeIF.java @@ -0,0 +1,13 @@ +public class Car{ + + private int speed; + + public void getSpeed(boolean boo){ + if(boo){ + + } else { + + } + } + +} \ No newline at end of file From 4d21d8e94e9f17548ddde560aadb6f4dd650af77 Mon Sep 17 00:00:00 2001 From: Bruder John Date: Thu, 27 Jun 2024 15:17:05 +0200 Subject: [PATCH 06/11] fix method overlaoding semantic check --- src/main/java/semantic/SemanticAnalyzer.java | 6 ++--- .../SelectWrongMethodCauseParameter.java | 22 +++++++++++++++++++ .../typedAstFeaturesTests/CorrectTest.java | 2 +- .../SelectRightOverloadedMethod.java | 21 ++++++++++++++++++ 4 files changed, 46 insertions(+), 5 deletions(-) create mode 100644 src/test/resources/input/typedAstExceptionsTests/SelectWrongMethodCauseParameter.java create mode 100644 src/test/resources/input/typedAstFeaturesTests/SelectRightOverloadedMethod.java diff --git a/src/main/java/semantic/SemanticAnalyzer.java b/src/main/java/semantic/SemanticAnalyzer.java index 1f318f2..db9cac0 100644 --- a/src/main/java/semantic/SemanticAnalyzer.java +++ b/src/main/java/semantic/SemanticAnalyzer.java @@ -214,9 +214,7 @@ public class SemanticAnalyzer implements SemanticVisitor { @Override public TypeCheckResult analyze(ParameterNode toCheck) { - - - return new TypeCheckResult(true, null); + return new TypeCheckResult(true, toCheck.type); } @Override @@ -517,7 +515,7 @@ public class SemanticAnalyzer implements SemanticVisitor { for(int i = 0; i < method.getParameters().size(); i++){ var result1 = method.getParameters().get(i).accept(this); var result2 = toCheck.parameters.get(i).accept(this); - if (Objects.equals(result1.getType(), result2.getType())) { + if (!Objects.equals(result1.getType(), result2.getType())) { same = false; } } diff --git a/src/test/resources/input/typedAstExceptionsTests/SelectWrongMethodCauseParameter.java b/src/test/resources/input/typedAstExceptionsTests/SelectWrongMethodCauseParameter.java new file mode 100644 index 0000000..f65e757 --- /dev/null +++ b/src/test/resources/input/typedAstExceptionsTests/SelectWrongMethodCauseParameter.java @@ -0,0 +1,22 @@ +// @expected: TypeMismatchException +public class Test{ + + public int i; + public boolean b; + + public int test(){ + + return this.test(i); + + } + + public void test(int a){ + + } + + public int test(boolean bool){ + int ret = 1; + return ret; + } + +} \ No newline at end of file diff --git a/src/test/resources/input/typedAstFeaturesTests/CorrectTest.java b/src/test/resources/input/typedAstFeaturesTests/CorrectTest.java index e5219be..bcb6b9c 100644 --- a/src/test/resources/input/typedAstFeaturesTests/CorrectTest.java +++ b/src/test/resources/input/typedAstFeaturesTests/CorrectTest.java @@ -5,7 +5,7 @@ public class Test{ public int test(){ - return i; + return this.test(b); } diff --git a/src/test/resources/input/typedAstFeaturesTests/SelectRightOverloadedMethod.java b/src/test/resources/input/typedAstFeaturesTests/SelectRightOverloadedMethod.java new file mode 100644 index 0000000..bcb6b9c --- /dev/null +++ b/src/test/resources/input/typedAstFeaturesTests/SelectRightOverloadedMethod.java @@ -0,0 +1,21 @@ +public class Test{ + + public int i; + public boolean b; + + public int test(){ + + return this.test(b); + + } + + public void test(int a){ + + } + + public int test(boolean bool){ + int ret = 1; + return ret; + } + +} \ No newline at end of file From f3e3158460f5332850f1b30dad13dcaf19aa1a17 Mon Sep 17 00:00:00 2001 From: Bruder John Date: Mon, 1 Jul 2024 12:58:11 +0200 Subject: [PATCH 07/11] added private fields --- src/main/java/semantic/SemanticAnalyzer.java | 26 ++++++++++++++--- .../java/semantic/context/FieldContext.java | 4 +++ .../FieldIsNotVisible.java | 20 +++++++++++++ .../typedAstFeaturesTests/CorrectTest.java | 29 +++++++++++-------- 4 files changed, 63 insertions(+), 16 deletions(-) create mode 100644 src/test/resources/input/typedAstExceptionsTests/FieldIsNotVisible.java diff --git a/src/main/java/semantic/SemanticAnalyzer.java b/src/main/java/semantic/SemanticAnalyzer.java index db9cac0..7f6e9a4 100644 --- a/src/main/java/semantic/SemanticAnalyzer.java +++ b/src/main/java/semantic/SemanticAnalyzer.java @@ -24,6 +24,7 @@ import ast.statementexpressions.crementexpressions.IncrementNode; import ast.statementexpressions.methodcallstatementnexpressions.MethodCallNode; import ast.statementexpressions.methodcallstatementnexpressions.TargetNode; import ast.statements.*; +import ast.type.AccessModifierNode; import ast.type.EnumAccessModifierNode; import ast.type.ValueNode; import ast.type.type.*; @@ -411,8 +412,18 @@ public class SemanticAnalyzer implements SemanticVisitor { } @Override - public TypeCheckResult analyze(NonCalculationNode toCheck) { - return null; + public TypeCheckResult analyze(NonCalculationNode nonCalculationNode) { + + var expResult = nonCalculationNode.expression.accept(this); + var unaryResult = nonCalculationNode.unaryExpression.accept(this); + + if(Objects.equals(expResult.getType(), unaryResult.getType())){ + return new TypeCheckResult(expResult.isValid() && unaryResult.isValid(), expResult.getType()); + } else { + errors.add(new TypeMismatchException("NonCalculation node " + nonCalculationNode.getType() + " does not match expression " + expResult.getType())); + } + + return new TypeCheckResult(false, null); } @Override @@ -437,9 +448,12 @@ public class SemanticAnalyzer implements SemanticVisitor { } else if(unary.value != null){ var result = unary.value.accept(this); return new TypeCheckResult(result.isValid(), result.getType()); + } else if(unary.memberAccess != null){ + var result = unary.memberAccess.accept(this); + return new TypeCheckResult(result.isValid(), result.getType()); } - return new TypeCheckResult(valid, null); + return new TypeCheckResult(false, null); } @Override @@ -464,7 +478,11 @@ public class SemanticAnalyzer implements SemanticVisitor { var currentTypeClass = context.getClass(reference.getIdentifier()); var currentField = currentTypeClass.getField(s); - currentType = currentField.getType(); + if(currentField.getAccessModifier().accessType == EnumAccessModifierNode.PUBLIC){ + currentType = currentField.getType(); + } else { + errors.add(new NotVisibleException("This field is not visible")); + return new TypeCheckResult(false, null); } } } diff --git a/src/main/java/semantic/context/FieldContext.java b/src/main/java/semantic/context/FieldContext.java index 8443520..aba5ba0 100644 --- a/src/main/java/semantic/context/FieldContext.java +++ b/src/main/java/semantic/context/FieldContext.java @@ -18,4 +18,8 @@ public class FieldContext { return type; } + public AccessModifierNode getAccessModifier() { + return accessModifier; + } + } diff --git a/src/test/resources/input/typedAstExceptionsTests/FieldIsNotVisible.java b/src/test/resources/input/typedAstExceptionsTests/FieldIsNotVisible.java new file mode 100644 index 0000000..ce099d3 --- /dev/null +++ b/src/test/resources/input/typedAstExceptionsTests/FieldIsNotVisible.java @@ -0,0 +1,20 @@ +// @expected: NotVisibleException +public class Test{ + + public Car c; + + public int test(){ + return c.speed; + } + +} + +public class Car{ + + private int speed; + + public int getSpeed(){ + return speed; + } + +} \ No newline at end of file diff --git a/src/test/resources/input/typedAstFeaturesTests/CorrectTest.java b/src/test/resources/input/typedAstFeaturesTests/CorrectTest.java index bcb6b9c..f908225 100644 --- a/src/test/resources/input/typedAstFeaturesTests/CorrectTest.java +++ b/src/test/resources/input/typedAstFeaturesTests/CorrectTest.java @@ -1,21 +1,26 @@ -public class Test{ - public int i; - public boolean b; +public class Test { - public int test(){ - - return this.test(b); + public Car c; + public int test(boolean b, int x) { + if (b == true) { + return c.getSpeed(); + } else { + x++; + return x; + } } - public void test(int a){ +} +public class Car { + + private int speed; + + public int getSpeed() { + return speed; } - public int test(boolean bool){ - int ret = 1; - return ret; - } +} -} \ No newline at end of file From 36e56fa66e80e99f0622008f1dac2909c0584b09 Mon Sep 17 00:00:00 2001 From: Bruder John Date: Mon, 1 Jul 2024 12:58:24 +0200 Subject: [PATCH 08/11] added some tests --- .../CompareBoolInt.java | 13 ++++++++++ .../CorrectMemberAccess.java | 19 ++++++++++++++ .../CorrectNonCalcTest.java | 12 +++++++++ .../input/typedAstFeaturesTests/FullTest.java | 25 +++++++++++++++++++ 4 files changed, 69 insertions(+) create mode 100644 src/test/resources/input/typedAstExceptionsTests/CompareBoolInt.java create mode 100644 src/test/resources/input/typedAstFeaturesTests/CorrectMemberAccess.java create mode 100644 src/test/resources/input/typedAstFeaturesTests/CorrectNonCalcTest.java create mode 100644 src/test/resources/input/typedAstFeaturesTests/FullTest.java diff --git a/src/test/resources/input/typedAstExceptionsTests/CompareBoolInt.java b/src/test/resources/input/typedAstExceptionsTests/CompareBoolInt.java new file mode 100644 index 0000000..1eb080a --- /dev/null +++ b/src/test/resources/input/typedAstExceptionsTests/CompareBoolInt.java @@ -0,0 +1,13 @@ +// @expected: TypeMismatchException +public class Test{ + + public void test(boolean b){ + if(b == 2){ + + } else { + + } + + } + +} diff --git a/src/test/resources/input/typedAstFeaturesTests/CorrectMemberAccess.java b/src/test/resources/input/typedAstFeaturesTests/CorrectMemberAccess.java new file mode 100644 index 0000000..b9f3dbb --- /dev/null +++ b/src/test/resources/input/typedAstFeaturesTests/CorrectMemberAccess.java @@ -0,0 +1,19 @@ +public class Test{ + + public Car c; + + public int test(){ + return c.getSpeed(); + } + +} + +public class Car{ + + private int speed; + + public int getSpeed(){ + return speed; + } + +} \ No newline at end of file diff --git a/src/test/resources/input/typedAstFeaturesTests/CorrectNonCalcTest.java b/src/test/resources/input/typedAstFeaturesTests/CorrectNonCalcTest.java new file mode 100644 index 0000000..d78e926 --- /dev/null +++ b/src/test/resources/input/typedAstFeaturesTests/CorrectNonCalcTest.java @@ -0,0 +1,12 @@ +public class Test{ + + public void test(boolean b){ + if(b == true){ + + } else { + + } + + } + +} diff --git a/src/test/resources/input/typedAstFeaturesTests/FullTest.java b/src/test/resources/input/typedAstFeaturesTests/FullTest.java new file mode 100644 index 0000000..b2191b3 --- /dev/null +++ b/src/test/resources/input/typedAstFeaturesTests/FullTest.java @@ -0,0 +1,25 @@ + +public class Test { + + public Car c; + + public int test(boolean b, int x) { + if (b == true) { + return c.getSpeed(); + } else { + return x; + } + } + +} + +public class Car { + + private int speed; + + public int getSpeed() { + return speed; + } + +} + From 77fecfa476ce9ba2858915f63d8b26fa58f0cf15 Mon Sep 17 00:00:00 2001 From: Bruder John Date: Mon, 1 Jul 2024 13:25:27 +0200 Subject: [PATCH 09/11] added Type to Assignable --- .../java/ast/expressions/IExpressionNode.java | 2 ++ .../binaryexpressions/BinaryNode.java | 9 ++++++- .../binaryexpressions/CalculationNode.java | 6 +---- .../binaryexpressions/DotNode.java | 5 ---- .../DotSubstractionNode.java | 5 ---- .../binaryexpressions/NonCalculationNode.java | 5 ---- .../unaryexpressions/MemberAccessNode.java | 10 ++++++++ .../statementexpressions/AssignableNode.java | 10 ++++++++ src/main/java/semantic/SemanticAnalyzer.java | 24 +++++++++++-------- .../typedAstFeaturesTests/CorrectTest.java | 3 +++ 10 files changed, 48 insertions(+), 31 deletions(-) diff --git a/src/main/java/ast/expressions/IExpressionNode.java b/src/main/java/ast/expressions/IExpressionNode.java index d1d380b..1a7a59e 100644 --- a/src/main/java/ast/expressions/IExpressionNode.java +++ b/src/main/java/ast/expressions/IExpressionNode.java @@ -8,4 +8,6 @@ public interface IExpressionNode extends ASTNode, Visitable { ITypeNode getType(); + void setType(ITypeNode type); + } diff --git a/src/main/java/ast/expressions/binaryexpressions/BinaryNode.java b/src/main/java/ast/expressions/binaryexpressions/BinaryNode.java index 9bfe8c2..f02aa2f 100644 --- a/src/main/java/ast/expressions/binaryexpressions/BinaryNode.java +++ b/src/main/java/ast/expressions/binaryexpressions/BinaryNode.java @@ -7,6 +7,8 @@ import typechecker.TypeCheckResult; public class BinaryNode implements IExpressionNode { + private ITypeNode typeNode; + @Override public TypeCheckResult accept(SemanticVisitor visitor) { return visitor.analyze(this); @@ -14,6 +16,11 @@ public class BinaryNode implements IExpressionNode { @Override public ITypeNode getType() { - return null; + return typeNode; + } + + @Override + public void setType(ITypeNode type) { + this.typeNode = type; } } diff --git a/src/main/java/ast/expressions/binaryexpressions/CalculationNode.java b/src/main/java/ast/expressions/binaryexpressions/CalculationNode.java index 4dec81a..f97d957 100644 --- a/src/main/java/ast/expressions/binaryexpressions/CalculationNode.java +++ b/src/main/java/ast/expressions/binaryexpressions/CalculationNode.java @@ -8,6 +8,7 @@ public class CalculationNode extends BinaryNode { public CalculationNode calculationExpression; public EnumLineOperator operator; public DotNode dotExpression; + private ITypeNode typeNode; public CalculationNode(CalculationNode calculationExpression, String operator, DotNode dotExpression) { this.calculationExpression = calculationExpression; @@ -32,9 +33,4 @@ public class CalculationNode extends BinaryNode { return visitor.analyze(this); } - @Override - public ITypeNode getType() { - return null; - } - } diff --git a/src/main/java/ast/expressions/binaryexpressions/DotNode.java b/src/main/java/ast/expressions/binaryexpressions/DotNode.java index 4cad9ec..0b31b01 100644 --- a/src/main/java/ast/expressions/binaryexpressions/DotNode.java +++ b/src/main/java/ast/expressions/binaryexpressions/DotNode.java @@ -34,9 +34,4 @@ public class DotNode extends BinaryNode { return visitor.analyze(this); } - @Override - public ITypeNode getType() { - return null; - } - } diff --git a/src/main/java/ast/expressions/binaryexpressions/DotSubstractionNode.java b/src/main/java/ast/expressions/binaryexpressions/DotSubstractionNode.java index 9537e15..812c58c 100644 --- a/src/main/java/ast/expressions/binaryexpressions/DotSubstractionNode.java +++ b/src/main/java/ast/expressions/binaryexpressions/DotSubstractionNode.java @@ -36,9 +36,4 @@ public class DotSubstractionNode extends BinaryNode { return visitor.analyze(this); } - @Override - public ITypeNode getType() { - return null; - } - } diff --git a/src/main/java/ast/expressions/binaryexpressions/NonCalculationNode.java b/src/main/java/ast/expressions/binaryexpressions/NonCalculationNode.java index d07a5f6..df0489b 100644 --- a/src/main/java/ast/expressions/binaryexpressions/NonCalculationNode.java +++ b/src/main/java/ast/expressions/binaryexpressions/NonCalculationNode.java @@ -42,9 +42,4 @@ public class NonCalculationNode extends BinaryNode { return visitor.analyze(this); } - @Override - public ITypeNode getType() { - return null; - } - } diff --git a/src/main/java/ast/expressions/unaryexpressions/MemberAccessNode.java b/src/main/java/ast/expressions/unaryexpressions/MemberAccessNode.java index e171f79..3ce6471 100644 --- a/src/main/java/ast/expressions/unaryexpressions/MemberAccessNode.java +++ b/src/main/java/ast/expressions/unaryexpressions/MemberAccessNode.java @@ -1,6 +1,7 @@ package ast.expressions.unaryexpressions; import ast.ASTNode; +import ast.type.type.ITypeNode; import semantic.SemanticVisitor; import typechecker.TypeCheckResult; import visitor.Visitable; @@ -11,6 +12,7 @@ import java.util.List; public class MemberAccessNode implements ASTNode, Visitable { public Boolean thisExpr; public List identifiers = new ArrayList<>(); + private ITypeNode typeNode; public MemberAccessNode(Boolean thisExpr) { this.thisExpr = thisExpr; @@ -25,4 +27,12 @@ public class MemberAccessNode implements ASTNode, Visitable { return visitor.analyze(this); } + public ITypeNode getTypeNode() { + return typeNode; + } + + public void setTypeNode(ITypeNode typeNode) { + this.typeNode = typeNode; + } + } diff --git a/src/main/java/ast/statementexpressions/AssignableNode.java b/src/main/java/ast/statementexpressions/AssignableNode.java index d3a1677..83568d8 100644 --- a/src/main/java/ast/statementexpressions/AssignableNode.java +++ b/src/main/java/ast/statementexpressions/AssignableNode.java @@ -1,11 +1,13 @@ package ast.statementexpressions; import ast.expressions.unaryexpressions.MemberAccessNode; +import ast.type.type.ITypeNode; import semantic.SemanticVisitor; import typechecker.TypeCheckResult; public class AssignableNode implements IStatementExpressionNode { public String identifier; + private ITypeNode typeNode; public MemberAccessNode memberAccess; @@ -22,4 +24,12 @@ public class AssignableNode implements IStatementExpressionNode { return visitor.analyze(this); } + public ITypeNode getTypeNode() { + return typeNode; + } + + public void setTypeNode(ITypeNode typeNode) { + this.typeNode = typeNode; + } + } diff --git a/src/main/java/semantic/SemanticAnalyzer.java b/src/main/java/semantic/SemanticAnalyzer.java index 7f6e9a4..6d2eeec 100644 --- a/src/main/java/semantic/SemanticAnalyzer.java +++ b/src/main/java/semantic/SemanticAnalyzer.java @@ -239,10 +239,19 @@ public class SemanticAnalyzer implements SemanticVisitor { @Override public TypeCheckResult analyze(AssignableNode toCheck) { - if (currentFields.get(toCheck.identifier) != null) { - return new TypeCheckResult(true, currentFields.get(toCheck.identifier)); - } else if (currentScope.getLocalVar(toCheck.identifier) != null) { - return new TypeCheckResult(true, currentScope.getLocalVar(toCheck.identifier)); + if(toCheck.memberAccess != null){ + var result = toCheck.memberAccess.accept(this); + toCheck.setTypeNode(result.getType()); + return result; + } else { + if (currentFields.get(toCheck.identifier) != null) { + var type = currentFields.get(toCheck.identifier); + toCheck.setTypeNode(type); + return new TypeCheckResult(true, type); + } else if (currentScope.getLocalVar(toCheck.identifier) != null) { + var type = currentScope.getLocalVar(toCheck.identifier); + return new TypeCheckResult(true, type); + } } return new TypeCheckResult(true, null); @@ -280,12 +289,7 @@ public class SemanticAnalyzer implements SemanticVisitor { currentNullType = lResult.getType(); var rResult = rExpression.accept(this); - var variable = currentScope.getLocalVar(toCheck.assignable.identifier); - if (variable == null) { - variable = currentFields.get(toCheck.assignable.identifier); - } - - if (!Objects.equals(variable, rResult.getType())) { + if (!Objects.equals(lResult.getType(), rResult.getType())) { errors.add(new TypeMismatchException( "Mismatch types in Assign-Statement: cannot convert from \"" + lResult.getType() + "\" to \"" + rResult.getType() + "\"")); diff --git a/src/test/resources/input/typedAstFeaturesTests/CorrectTest.java b/src/test/resources/input/typedAstFeaturesTests/CorrectTest.java index f908225..bf12c55 100644 --- a/src/test/resources/input/typedAstFeaturesTests/CorrectTest.java +++ b/src/test/resources/input/typedAstFeaturesTests/CorrectTest.java @@ -22,5 +22,8 @@ public class Car { return speed; } + public void setSpeed(int speed) { + this.speed = speed; + } } From 2d455ba197e4168cb87eda0f380fa159ed64c536 Mon Sep 17 00:00:00 2001 From: Bruder John Date: Mon, 1 Jul 2024 15:45:57 +0200 Subject: [PATCH 10/11] added som more checks --- .../java/ast/members/ConstructorNode.java | 15 ++ src/main/java/ast/members/MainMethodNode.java | 1 - src/main/java/ast/statements/WhileNode.java | 6 +- src/main/java/semantic/SemanticAnalyzer.java | 193 ++++++++++++------ .../BothTypesMustBeSame1.java | 9 + .../typedAstFeaturesTests/CorrectTest.java | 55 ++--- .../input/typedAstFeaturesTests/FullTest.java | 39 ++++ 7 files changed, 225 insertions(+), 93 deletions(-) create mode 100644 src/test/resources/input/typedAstExceptionsTests/BothTypesMustBeSame1.java diff --git a/src/main/java/ast/members/ConstructorNode.java b/src/main/java/ast/members/ConstructorNode.java index d6a40c2..2d5400d 100644 --- a/src/main/java/ast/members/ConstructorNode.java +++ b/src/main/java/ast/members/ConstructorNode.java @@ -6,6 +6,7 @@ import ast.type.AccessModifierNode; import java.util.ArrayList; import java.util.List; +import java.util.Objects; public class ConstructorNode extends MethodNode { public AccessModifierNode accessType; @@ -23,4 +24,18 @@ public class ConstructorNode extends MethodNode { parameters.add(parameterNode); } + @Override + public boolean isSame(MethodNode methodNode) { + if (!(Objects.equals(this.identifier, methodNode.getIdentifier())) + || getParameters().size() != methodNode.getParameters().size()) { + return false; + } + + for (int i = 0; i < this.getParameters().size(); i++) { + if (!this.getParameters().get(i).type.equals(methodNode.getParameters().get(i).type)) { + return false; + } + } + return true; + } } diff --git a/src/main/java/ast/members/MainMethodNode.java b/src/main/java/ast/members/MainMethodNode.java index 3ae01a2..4680a26 100644 --- a/src/main/java/ast/members/MainMethodNode.java +++ b/src/main/java/ast/members/MainMethodNode.java @@ -3,7 +3,6 @@ package ast.members; import ast.statements.BlockNode; public class MainMethodNode extends MethodNode { - public BlockNode block; public MainMethodNode(BlockNode block) { this.block = block; diff --git a/src/main/java/ast/statements/WhileNode.java b/src/main/java/ast/statements/WhileNode.java index 01c1160..ee93167 100644 --- a/src/main/java/ast/statements/WhileNode.java +++ b/src/main/java/ast/statements/WhileNode.java @@ -6,8 +6,8 @@ import semantic.SemanticVisitor; import typechecker.TypeCheckResult; public class WhileNode implements IStatementNode { - IExpressionNode expression; - BlockNode block; + public IExpressionNode expression; + public BlockNode block; public WhileNode(IExpressionNode expression, BlockNode block) { this.expression = expression; @@ -21,6 +21,6 @@ public class WhileNode implements IStatementNode { @Override public TypeCheckResult accept(SemanticVisitor visitor) { - return null; + return visitor.analyze(this); } } diff --git a/src/main/java/semantic/SemanticAnalyzer.java b/src/main/java/semantic/SemanticAnalyzer.java index 6d2eeec..6ebd124 100644 --- a/src/main/java/semantic/SemanticAnalyzer.java +++ b/src/main/java/semantic/SemanticAnalyzer.java @@ -140,18 +140,14 @@ public class SemanticAnalyzer implements SemanticVisitor { } } - // Check if this method is already declared currentMethodReturnType = methodNode.getType(); - currentNullType = currentMethodReturnType; // Solange nicht in einem Assign oder Methoden-Aufruf dieser Typ + currentNullType = currentMethodReturnType; - ITypeNode resultType = new BaseType(TypeEnum.VOID); - - // gesetzt ist, ist dieser der Rückgabewert der Methode var result = methodNode.block.accept(this); valid = valid && result.isValid(); currentScope.popScope(); - resultType = result.getType(); + ITypeNode resultType = result.getType(); if (resultType == null) { resultType = new BaseType(TypeEnum.VOID); @@ -181,8 +177,8 @@ public class SemanticAnalyzer implements SemanticVisitor { toCheck.block.accept(this); var resultExpression = toCheck.expression.accept(this); - if(resultExpression.isValid()){ - if(!resultExpression.getType().equals(new BaseType(TypeEnum.BOOL))){ + if (resultExpression.isValid()) { + if (!resultExpression.getType().equals(new BaseType(TypeEnum.BOOL))) { errors.add(new TypeMismatchException("Expression must be Boolean")); return new TypeCheckResult(false, new BaseType(TypeEnum.VOID)); } @@ -195,8 +191,8 @@ public class SemanticAnalyzer implements SemanticVisitor { public TypeCheckResult analyze(ReturnNode toCheck) { if (toCheck.expression != null) { var result = toCheck.expression.accept(this); - if(result.isValid()){ - if(!result.getType().equals(currentMethodReturnType)){ + if (result.isValid()) { + if (!result.getType().equals(currentMethodReturnType)) { errors.add(new TypeMismatchException("Mismatched return Type from method")); } } @@ -210,7 +206,9 @@ public class SemanticAnalyzer implements SemanticVisitor { @Override public TypeCheckResult analyze(WhileNode toCheck) { - return null; + var expResult = toCheck.expression.accept(this); + var blockRes = toCheck.block.accept(this); + return new TypeCheckResult(expResult.isValid() && blockRes.isValid(), blockRes.getType()); } @Override @@ -221,14 +219,19 @@ public class SemanticAnalyzer implements SemanticVisitor { @Override public TypeCheckResult analyze(BlockNode blockNode) { ITypeNode blockReturnType = null; + if (blockNode.statements.isEmpty()) { + return new TypeCheckResult(true, null); + } for (IStatementNode statementNode : blockNode.statements) { var result = statementNode.accept(this); - if (result.getType() != null) { - if (blockReturnType == null) { - blockReturnType = result.getType(); - } else { - if(!blockReturnType.equals(result.getType())) { - errors.add(new MultipleReturnTypes("There are multiple Return types")); + if(!(statementNode instanceof IncrementNode) && !(statementNode instanceof DecrementNode)){ + if (result.getType() != null) { + if (blockReturnType == null) { + blockReturnType = result.getType(); + } else { + if (!blockReturnType.equals(result.getType())) { + errors.add(new MultipleReturnTypes("There are multiple Return types")); + } } } } @@ -239,7 +242,7 @@ public class SemanticAnalyzer implements SemanticVisitor { @Override public TypeCheckResult analyze(AssignableNode toCheck) { - if(toCheck.memberAccess != null){ + if (toCheck.memberAccess != null) { var result = toCheck.memberAccess.accept(this); toCheck.setTypeNode(result.getType()); return result; @@ -260,8 +263,7 @@ public class SemanticAnalyzer implements SemanticVisitor { @Override public TypeCheckResult analyze(ElseNode toCheck) { - toCheck.block.accept(this); - return null; + return toCheck.block.accept(this); } @Override @@ -308,10 +310,9 @@ public class SemanticAnalyzer implements SemanticVisitor { @Override public TypeCheckResult analyze(IfElseNode toCheck) { var resultIf = toCheck.ifStatement.accept(this); - var resultElse = toCheck.elseStatement.accept(this); - return new TypeCheckResult(true, new BaseType(TypeEnum.VOID)); + return new TypeCheckResult(resultIf.isValid() && resultElse.isValid(), new BaseType(TypeEnum.VOID)); } @Override @@ -323,18 +324,18 @@ public class SemanticAnalyzer implements SemanticVisitor { targetType = currentFields.get(toCheck.target.identifier); } if (targetType instanceof ReferenceType reference) { - var type = getTypeFromMethod(toCheck, reference); - if(type != null){ + var type = getTypeFromMethod(toCheck, reference); + if (type != null) { return new TypeCheckResult(true, type); - }else { + } else { return new TypeCheckResult(false, null); } } } else { - if(toCheck.target.thisTar){ - var type = getTypeFromMethod(toCheck, new ReferenceType(currentClass.identifier)); - if(type != null){ + if (toCheck.target.thisTar) { + var type = getTypeFromMethod(toCheck, new ReferenceType(currentClass.identifier)); + if (type != null) { return new TypeCheckResult(true, type); } } else { @@ -355,7 +356,7 @@ public class SemanticAnalyzer implements SemanticVisitor { TypeCheckResult result = localVarDecl.expression.accept(this); var resultType = localVarDecl.expression.getType(); - if(result.getType() != null){ + if (result.getType() != null) { resultType = result.getType(); } valid = result.isValid() && valid; @@ -400,33 +401,89 @@ public class SemanticAnalyzer implements SemanticVisitor { @Override public TypeCheckResult analyze(CalculationNode calcNode) { if (calcNode.calculationExpression != null) { - calcNode.calculationExpression.accept(this); + var calcRes = calcNode.calculationExpression.accept(this); + if (calcNode.dotExpression != null) { + var dotRes = calcNode.dotExpression.accept(this); + + switch (calcNode.operator) { + case PLUS, MINUS: + if (calcRes.getType() instanceof BaseType calcType && dotRes.getType() instanceof BaseType dotType && + calcType.getTypeEnum().equals(TypeEnum.INT) && dotType.getTypeEnum().equals(TypeEnum.INT)) { + return new TypeCheckResult(true, new BaseType(TypeEnum.INT)); + } + break; + default: + } + + } else { + return new TypeCheckResult(calcRes.isValid(), calcRes.getType()); + } + } else if (calcNode.dotExpression != null) { + var dotRes = calcNode.dotExpression.accept(this); + return new TypeCheckResult(dotRes.isValid(), dotRes.getType()); } - return null; + return new TypeCheckResult(false, null); } @Override public TypeCheckResult analyze(DotNode toCheck) { - return null; + if (toCheck.dotSubstractionExpression != null) { + return toCheck.dotSubstractionExpression.accept(this); + } + return new TypeCheckResult(false, null); } @Override public TypeCheckResult analyze(DotSubstractionNode toCheck) { + if (toCheck.value != null) { + return toCheck.value.accept(this); + } else if (toCheck.memberAccess != null) { + return toCheck.memberAccess.accept(this); + } else if (toCheck.methodCall != null) { + return toCheck.methodCall.accept(this); + } else if (toCheck.identifier != null) { + if (currentScope.contains(toCheck.identifier)) { + return new TypeCheckResult(true, currentScope.getLocalVar(toCheck.identifier)); + } else if (currentFields.get(toCheck.identifier) != null) { + return new TypeCheckResult(true, currentFields.get(toCheck.identifier)); + } + } else if (toCheck.calculationExpression != null) { + return toCheck.calculationExpression.accept(this); + } return null; } @Override public TypeCheckResult analyze(NonCalculationNode nonCalculationNode) { - var expResult = nonCalculationNode.expression.accept(this); var unaryResult = nonCalculationNode.unaryExpression.accept(this); - if(Objects.equals(expResult.getType(), unaryResult.getType())){ - return new TypeCheckResult(expResult.isValid() && unaryResult.isValid(), expResult.getType()); - } else { - errors.add(new TypeMismatchException("NonCalculation node " + nonCalculationNode.getType() + " does not match expression " + expResult.getType())); - } + switch (nonCalculationNode.operator) { + case LESS, LESS_EQUAL, GREATER, GREATER_EQUAL: + if (expResult.getType() instanceof BaseType expResultType && expResultType.getTypeEnum().equals(TypeEnum.INT) && + unaryResult.getType() instanceof BaseType unaryResultType && unaryResultType.getTypeEnum().equals(TypeEnum.INT)) { + return new TypeCheckResult(true, new BaseType(TypeEnum.BOOL)); + } else { + errors.add(new TypeMismatchException("Both types must be Integer")); + } + break; + case OR, AND: + if (expResult.getType() instanceof BaseType expResultType && expResultType.getTypeEnum().equals(TypeEnum.INT) && + unaryResult.getType() instanceof BaseType unaryResultType && unaryResultType.getTypeEnum().equals(TypeEnum.INT)) { + return new TypeCheckResult(true, new BaseType(TypeEnum.BOOL)); + } else { + errors.add(new TypeMismatchException("Both types must be Boolean")); + } + break; + case EQUAL, NOT_EQUAL: + if (expResult.getType() instanceof BaseType expResultType && unaryResult.getType() instanceof BaseType unaryResultType + && Objects.equals(expResultType, unaryResultType)) { + return new TypeCheckResult(true, new BaseType(TypeEnum.BOOL)); + } else { + errors.add(new TypeMismatchException("Both types must be the same")); + } + } return new TypeCheckResult(false, null); } @@ -434,7 +491,7 @@ public class SemanticAnalyzer implements SemanticVisitor { public TypeCheckResult analyze(UnaryNode unary) { var valid = true; - if(unary.identifier != null){ + if (unary.identifier != null) { if (currentScope.contains(unary.identifier)) { return new TypeCheckResult(valid, currentScope.getLocalVar(unary.identifier)); } else if (currentFields.get(unary.identifier) != null) { @@ -446,15 +503,18 @@ public class SemanticAnalyzer implements SemanticVisitor { } else { errors.add(new NotDeclaredException("Var is not Declared")); } - } else if (unary.statement != null){ + } else if (unary.statement != null) { var result = unary.statement.accept(this); return new TypeCheckResult(result.isValid(), result.getType()); - } else if(unary.value != null){ + } else if (unary.value != null) { var result = unary.value.accept(this); return new TypeCheckResult(result.isValid(), result.getType()); - } else if(unary.memberAccess != null){ + } else if (unary.memberAccess != null) { var result = unary.memberAccess.accept(this); return new TypeCheckResult(result.isValid(), result.getType()); + } else if (unary.expression != null) { + var result = unary.expression.accept(this); + return new TypeCheckResult(result.isValid(), result.getType()); } return new TypeCheckResult(false, null); @@ -478,15 +538,16 @@ public class SemanticAnalyzer implements SemanticVisitor { } } else { - if(currentType instanceof ReferenceType reference) { + if (currentType instanceof ReferenceType reference) { var currentTypeClass = context.getClass(reference.getIdentifier()); var currentField = currentTypeClass.getField(s); - if(currentField.getAccessModifier().accessType == EnumAccessModifierNode.PUBLIC){ + if (currentField.getAccessModifier().accessType == EnumAccessModifierNode.PUBLIC) { currentType = currentField.getType(); } else { errors.add(new NotVisibleException("This field is not visible")); - return new TypeCheckResult(false, null); } + return new TypeCheckResult(false, null); + } } } @@ -507,20 +568,20 @@ public class SemanticAnalyzer implements SemanticVisitor { @Override public TypeCheckResult analyze(ValueNode valueNode) { - switch (valueNode.valueType){ - case INT_VALUE -> { - return new TypeCheckResult(true, new BaseType(TypeEnum.INT)); - } - case CHAR_VALUE -> { - return new TypeCheckResult(true, new BaseType(TypeEnum.CHAR)); - } - case BOOLEAN_VALUE -> { - return new TypeCheckResult(true, new BaseType(TypeEnum.BOOL)); - } - default -> { - return new TypeCheckResult(false, null); - } - } + switch (valueNode.valueType) { + case INT_VALUE -> { + return new TypeCheckResult(true, new BaseType(TypeEnum.INT)); + } + case CHAR_VALUE -> { + return new TypeCheckResult(true, new BaseType(TypeEnum.CHAR)); + } + case BOOLEAN_VALUE -> { + return new TypeCheckResult(true, new BaseType(TypeEnum.BOOL)); + } + default -> { + return new TypeCheckResult(false, null); + } + } } private ITypeNode getTypeFromMethod(MethodCallNode toCheck, ReferenceType reference) { @@ -532,22 +593,22 @@ public class SemanticAnalyzer implements SemanticVisitor { var methods = classContext.getMethods(); for (var method : methods) { if (toCheck.identifier.equals(method.getIdentifier())) { - if(method.getParameters().size() == toCheck.parameters.size() && !(method instanceof ConstructorNode)){ + if (method.getParameters().size() == toCheck.parameters.size() && !(method instanceof ConstructorNode)) { boolean same = true; - for(int i = 0; i < method.getParameters().size(); i++){ + for (int i = 0; i < method.getParameters().size(); i++) { var result1 = method.getParameters().get(i).accept(this); var result2 = toCheck.parameters.get(i).accept(this); - if (!Objects.equals(result1.getType(), result2.getType())) { + if (!Objects.equals(result1.getType(), result2.getType())) { same = false; } } - if(same){ - if(method.accesModifier.accessType == EnumAccessModifierNode.PUBLIC){ - if(method.getType() == null){ + if (same) { + if (method.accesModifier.accessType == EnumAccessModifierNode.PUBLIC) { + if (method.getType() == null) { return new BaseType(TypeEnum.VOID); } return method.getType(); - }else { + } else { errors.add(new NotVisibleException("This Method is not Visible")); } } diff --git a/src/test/resources/input/typedAstExceptionsTests/BothTypesMustBeSame1.java b/src/test/resources/input/typedAstExceptionsTests/BothTypesMustBeSame1.java new file mode 100644 index 0000000..5a88a45 --- /dev/null +++ b/src/test/resources/input/typedAstExceptionsTests/BothTypesMustBeSame1.java @@ -0,0 +1,9 @@ +// @expected: TypeMismatchException +public class AllFeaturesClassExample { + + public void controlStructures(int a, boolean bool) { + while (a > bool) { + a--; + } + } +} diff --git a/src/test/resources/input/typedAstFeaturesTests/CorrectTest.java b/src/test/resources/input/typedAstFeaturesTests/CorrectTest.java index bf12c55..73cd501 100644 --- a/src/test/resources/input/typedAstFeaturesTests/CorrectTest.java +++ b/src/test/resources/input/typedAstFeaturesTests/CorrectTest.java @@ -1,29 +1,38 @@ +public class AllFeaturesClassExample { + int a; + boolean b; + char c; -public class Test { + public void controlStructures(int adf, boolean bool) { +// if (a > (10 + 8)) { +// } else { +// } +// +// +// while (a > adf) { +// a--; +// } - public Car c; - - public int test(boolean b, int x) { - if (b == true) { - return c.getSpeed(); - } else { - x++; - return x; + for (int i = 0; i < 5; i++) { } + + } +// void logicalOperations() { +// // Logische UND-Operation +// if (b && a > 5) { +//// System.out.println("a ist größer als 5 und b ist wahr"); +// } +// +// // Logische ODER-Operation +// if (b || a < 5) { +//// System.out.println("b ist wahr oder a ist kleiner als 5"); +// } +// } + +// public static void main(String[] args) { +// AllFeaturesClassExample obj = new AllFeaturesClassExample(12, true, 'a'); +// obj.controlStructures(); +// } } - -public class Car { - - private int speed; - - public int getSpeed() { - return speed; - } - - public void setSpeed(int speed) { - this.speed = speed; - } -} - diff --git a/src/test/resources/input/typedAstFeaturesTests/FullTest.java b/src/test/resources/input/typedAstFeaturesTests/FullTest.java index b2191b3..21c3372 100644 --- a/src/test/resources/input/typedAstFeaturesTests/FullTest.java +++ b/src/test/resources/input/typedAstFeaturesTests/FullTest.java @@ -1,4 +1,43 @@ +public class AllFeaturesClassExample { + int a; + boolean b; + char c; + + public void controlStructures(int adf, boolean bool) { + if (a > (10 + 8)) { + } else { + } + + + while (a > adf) { + a--; + } + +// for (int i = 0; i < 5; i++) { +// } + + + } + +// void logicalOperations() { +// // Logische UND-Operation +// if (b && a > 5) { +//// System.out.println("a ist größer als 5 und b ist wahr"); +// } +// +// // Logische ODER-Operation +// if (b || a < 5) { +//// System.out.println("b ist wahr oder a ist kleiner als 5"); +// } +// } + +// public static void main(String[] args) { +// AllFeaturesClassExample obj = new AllFeaturesClassExample(12, true, 'a'); +// obj.controlStructures(); +// } +} + public class Test { public Car c; From 71ffb8bb83fbf6ec315fc633793e8e4dce9f531f Mon Sep 17 00:00:00 2001 From: Bruder John Date: Mon, 1 Jul 2024 16:04:27 +0200 Subject: [PATCH 11/11] added for loops to the test --- .../typedAstFeaturesTests/CorrectTest.java | 26 +++++++++---------- .../input/typedAstFeaturesTests/FullTest.java | 4 +-- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/test/resources/input/typedAstFeaturesTests/CorrectTest.java b/src/test/resources/input/typedAstFeaturesTests/CorrectTest.java index 73cd501..5ef0b26 100644 --- a/src/test/resources/input/typedAstFeaturesTests/CorrectTest.java +++ b/src/test/resources/input/typedAstFeaturesTests/CorrectTest.java @@ -4,14 +4,14 @@ public class AllFeaturesClassExample { char c; public void controlStructures(int adf, boolean bool) { -// if (a > (10 + 8)) { -// } else { -// } -// -// -// while (a > adf) { -// a--; -// } + if (a > (10 + 8)) { + } else { + } + + + while (a > adf) { + a--; + } for (int i = 0; i < 5; i++) { } @@ -20,14 +20,14 @@ public class AllFeaturesClassExample { } // void logicalOperations() { -// // Logische UND-Operation + // Logische UND-Operation // if (b && a > 5) { -//// System.out.println("a ist größer als 5 und b ist wahr"); +// System.out.println("a ist größer als 5 und b ist wahr"); // } -// -// // Logische ODER-Operation + + // Logische ODER-Operation // if (b || a < 5) { -//// System.out.println("b ist wahr oder a ist kleiner als 5"); +// System.out.println("b ist wahr oder a ist kleiner als 5"); // } // } diff --git a/src/test/resources/input/typedAstFeaturesTests/FullTest.java b/src/test/resources/input/typedAstFeaturesTests/FullTest.java index 21c3372..5c3a97b 100644 --- a/src/test/resources/input/typedAstFeaturesTests/FullTest.java +++ b/src/test/resources/input/typedAstFeaturesTests/FullTest.java @@ -14,8 +14,8 @@ public class AllFeaturesClassExample { a--; } -// for (int i = 0; i < 5; i++) { -// } + for (int i = 0; i < 5; i++) { + } }