added some Semantic Tests
Some checks are pending
Gitea Actions Demo / Explore-Gitea-Actions (push) Waiting to run

This commit is contained in:
Bruder John 2024-06-27 10:45:38 +02:00
parent 576146c4fc
commit 10eb17497e
17 changed files with 220 additions and 91 deletions

View File

@ -1,11 +1,14 @@
package ast.expressions.unaryexpressions; package ast.expressions.unaryexpressions;
import ast.ASTNode; import ast.ASTNode;
import semantic.SemanticVisitor;
import typechecker.TypeCheckResult;
import visitor.Visitable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
public class MemberAccessNode implements ASTNode { public class MemberAccessNode implements ASTNode, Visitable {
public Boolean thisExpr; public Boolean thisExpr;
public List<String> identifiers = new ArrayList<>(); public List<String> identifiers = new ArrayList<>();
@ -17,4 +20,9 @@ public class MemberAccessNode implements ASTNode {
identifiers.add(identifier); identifiers.add(identifier);
} }
@Override
public TypeCheckResult accept(SemanticVisitor visitor) {
return visitor.analyze(this);
}
} }

View File

@ -3,8 +3,11 @@ package ast.statementexpressions.methodcallstatementnexpressions;
import ast.ASTNode; import ast.ASTNode;
import ast.expressions.unaryexpressions.MemberAccessNode; import ast.expressions.unaryexpressions.MemberAccessNode;
import ast.statementexpressions.NewDeclarationNode; 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 Boolean thisTar;
public MemberAccessNode memberAccess; public MemberAccessNode memberAccess;
public NewDeclarationNode newDeclaration; public NewDeclarationNode newDeclaration;
@ -25,4 +28,11 @@ public class TargetNode implements ASTNode {
public TargetNode(String identifier) { public TargetNode(String identifier) {
this.identifier = identifier; this.identifier = identifier;
} }
@Override
public TypeCheckResult accept(SemanticVisitor visitor) {
return visitor.analyze(this);
}
} }

View File

@ -9,6 +9,7 @@ import java.util.Objects;
import ast.*; import ast.*;
import ast.expressions.IExpressionNode; import ast.expressions.IExpressionNode;
import ast.expressions.binaryexpressions.*; import ast.expressions.binaryexpressions.*;
import ast.expressions.unaryexpressions.MemberAccessNode;
import ast.expressions.unaryexpressions.UnaryNode; import ast.expressions.unaryexpressions.UnaryNode;
import ast.members.ConstructorNode; import ast.members.ConstructorNode;
import ast.members.FieldNode; import ast.members.FieldNode;
@ -21,7 +22,9 @@ import ast.statementexpressions.NewDeclarationNode;
import ast.statementexpressions.crementexpressions.DecrementNode; import ast.statementexpressions.crementexpressions.DecrementNode;
import ast.statementexpressions.crementexpressions.IncrementNode; import ast.statementexpressions.crementexpressions.IncrementNode;
import ast.statementexpressions.methodcallstatementnexpressions.MethodCallNode; import ast.statementexpressions.methodcallstatementnexpressions.MethodCallNode;
import ast.statementexpressions.methodcallstatementnexpressions.TargetNode;
import ast.statements.*; import ast.statements.*;
import ast.type.EnumAccessModifierNode;
import ast.type.type.*; import ast.type.type.*;
import semantic.context.Context; import semantic.context.Context;
import semantic.exceptions.*; import semantic.exceptions.*;
@ -150,7 +153,7 @@ public class SemanticAnalyzer implements SemanticVisitor {
if (resultType == null) { if (resultType == null) {
resultType = new BaseType(TypeEnum.VOID); resultType = new BaseType(TypeEnum.VOID);
} }
if(methodNode.getType() == null){ if (methodNode.getType() == null) {
methodNode.setType(new BaseType(TypeEnum.VOID)); methodNode.setType(new BaseType(TypeEnum.VOID));
} }
if (!resultType.equals(methodNode.getType())) { if (!resultType.equals(methodNode.getType())) {
@ -185,7 +188,7 @@ public class SemanticAnalyzer implements SemanticVisitor {
if (toCheck.expression != null) { if (toCheck.expression != null) {
var result = toCheck.expression.accept(this); var result = toCheck.expression.accept(this);
return new TypeCheckResult(true, result.getType()); 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(false, new BaseType(TypeEnum.VOID));
} }
return new TypeCheckResult(true, null); return new TypeCheckResult(true, null);
@ -223,7 +226,7 @@ public class SemanticAnalyzer implements SemanticVisitor {
@Override @Override
public TypeCheckResult analyze(AssignableNode toCheck) { 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)); return new TypeCheckResult(true, currentFields.get(toCheck.identifier));
} else if (currentScope.getLocalVar(toCheck.identifier) != null) { } else if (currentScope.getLocalVar(toCheck.identifier) != null) {
return new TypeCheckResult(true, currentScope.getLocalVar(toCheck.identifier)); return new TypeCheckResult(true, currentScope.getLocalVar(toCheck.identifier));
@ -264,19 +267,16 @@ public class SemanticAnalyzer implements SemanticVisitor {
var rResult = rExpression.accept(this); var rResult = rExpression.accept(this);
var variable = currentScope.getLocalVar(toCheck.assignable.identifier); var variable = currentScope.getLocalVar(toCheck.assignable.identifier);
if(variable == null){ if (variable == null) {
variable = currentFields.get(toCheck.assignable.identifier); variable = currentFields.get(toCheck.assignable.identifier);
} }
if (!Objects.equals(variable, rExpression.getType())) { if (!Objects.equals(variable, rResult.getType())) {
errors.add(new TypeMismatchException( errors.add(new TypeMismatchException(
"Mismatch types in Assign-Statement: cannot convert from \"" + lResult.getType() + "\" to \"" "Mismatch types in Assign-Statement: cannot convert from \"" + lResult.getType() + "\" to \""
+ rResult.getType() + "\"")); + rResult.getType() + "\""));
valid = false; valid = false;
} }
// else {
// toCheck.setType(assignable.getType());
// }
valid = valid && lResult.isValid() && rResult.isValid(); valid = valid && lResult.isValid() && rResult.isValid();
currentNullType = null; currentNullType = null;
return new TypeCheckResult(valid, null); // return type is null to get the return type sufficently 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 @Override
public TypeCheckResult analyze(MethodCallNode toCheck) { public TypeCheckResult analyze(MethodCallNode toCheck) {
var targetType = currentScope.getLocalVar(toCheck.target.identifier); if (toCheck.target.identifier != null) {
if(targetType == null){ var targetType = currentScope.getLocalVar(toCheck.target.identifier);
targetType = currentFields.get(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){ return null;
var classContext = context.getClass(reference.getIdentifier()); }
if(classContext == null){ private ITypeNode getTypeFromMethod(MethodCallNode toCheck, ReferenceType reference) {
errors.add(new NotDefinedException(toCheck.target.identifier + "is not Defined")); var classContext = context.getClass(reference.getIdentifier());
}else {
var methods = classContext.getMethods(); if (classContext == null) {
for (var method : methods) { errors.add(new NotDeclaredException(toCheck.target.identifier + "is not Defined"));
if(toCheck.identifier.equals(method.getIdentifier()) && method.getParameters().size() == toCheck.parameters.size()){ } else {
return new TypeCheckResult(true, method.getType()); 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; return null;
} }
@ -348,7 +366,7 @@ public class SemanticAnalyzer implements SemanticVisitor {
@Override @Override
public TypeCheckResult analyze(NewDeclarationNode toCheck) { public TypeCheckResult analyze(NewDeclarationNode toCheck) {
if(context.containsClass(toCheck.identifier)) { if (context.containsClass(toCheck.identifier)) {
return new TypeCheckResult(true, new ReferenceType(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")); errors.add(new NotDeclaredException("Var is not Declared"));
} }
return new TypeCheckResult(valid, null); 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;
}
} }

View File

@ -2,6 +2,7 @@ package semantic;
import ast.*; import ast.*;
import ast.expressions.binaryexpressions.*; import ast.expressions.binaryexpressions.*;
import ast.expressions.unaryexpressions.MemberAccessNode;
import ast.expressions.unaryexpressions.UnaryNode; import ast.expressions.unaryexpressions.UnaryNode;
import ast.members.*; import ast.members.*;
import ast.parameters.ParameterNode; import ast.parameters.ParameterNode;
@ -11,6 +12,7 @@ import ast.statementexpressions.NewDeclarationNode;
import ast.statementexpressions.crementexpressions.DecrementNode; import ast.statementexpressions.crementexpressions.DecrementNode;
import ast.statementexpressions.crementexpressions.IncrementNode; import ast.statementexpressions.crementexpressions.IncrementNode;
import ast.statementexpressions.methodcallstatementnexpressions.MethodCallNode; import ast.statementexpressions.methodcallstatementnexpressions.MethodCallNode;
import ast.statementexpressions.methodcallstatementnexpressions.TargetNode;
import ast.statements.*; import ast.statements.*;
import typechecker.TypeCheckResult; import typechecker.TypeCheckResult;
@ -38,8 +40,6 @@ public interface SemanticVisitor {
TypeCheckResult analyze(ElseNode toCheck); TypeCheckResult analyze(ElseNode toCheck);
//TypeCheckResult analyze(ForNode toCheck);
TypeCheckResult analyze(AssignNode toCheck); TypeCheckResult analyze(AssignNode toCheck);
TypeCheckResult analyze(DecrementNode toCheck); TypeCheckResult analyze(DecrementNode toCheck);
@ -66,4 +66,8 @@ public interface SemanticVisitor {
TypeCheckResult analyze(UnaryNode toCheck); TypeCheckResult analyze(UnaryNode toCheck);
TypeCheckResult analyze(MemberAccessNode toCheck);
TypeCheckResult analyze(TargetNode toCheck);
} }

View File

@ -0,0 +1,9 @@
package semantic.exceptions;
public class NotVisibleException extends RuntimeException {
public NotVisibleException(String message) {
super(message);
}
}

View File

@ -26,11 +26,37 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*; import static org.junit.jupiter.api.Assertions.*;
public class EndToTypedAstTest { public class EndToTypedAstTest {
private static final Map<String, Class<?>> exceptionMap = new HashMap<>(); private static final Map<String, Class<?>> 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 @Test
public void exceptionsTest() { public void exceptionsTest() {
String directoryPath = "src/test/resources/input/typedAstExceptionsTests"; String directoryPath = "src/test/resources/input/typedAstExceptionsTests";
@ -88,7 +114,7 @@ public class EndToTypedAstTest {
} }
@Test @Test
public void featureTest(){ public void featureTest() {
String directoryPath = "src/test/resources/input/typedAstFeaturesTests"; String directoryPath = "src/test/resources/input/typedAstFeaturesTests";
File folder = new File(directoryPath); File folder = new File(directoryPath);
if (folder.isDirectory()) { if (folder.isDirectory()) {
@ -127,9 +153,8 @@ public class EndToTypedAstTest {
} }
// ------------------ Helpers ------------------ // ------------------ Helpers ------------------
/** /**
* This method is used to extract the expected exception from a given file. * 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. * 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. * 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 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. * 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. * 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. * @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. * @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. * @throws RuntimeException If the Class object for the given exception name is not found in the exceptionMap.
*/ */
private Class<?> getExceptionClass(String exceptionName) { private Class<?> getExceptionClass(String exceptionName) {
System.out.println(exceptionName); System.out.println(exceptionName);
exceptionName = "semantic.exceptions." + exceptionName; exceptionName = "semantic.exceptions." + exceptionName;
System.out.println(exceptionName); System.out.println(exceptionName);
Class<?> exceptionClass = exceptionMap.get(exceptionName); Class<?> exceptionClass = exceptionMap.get(exceptionName);
if (exceptionClass == null) { if (exceptionClass == null) {
throw new RuntimeException("Exception class not found: " + exceptionName); throw new RuntimeException("Exception class not found: " + exceptionName);
}
return exceptionClass;
} }
return exceptionClass;
}
/** /**
* This method is used to load custom exceptions from a specified package. * This method is used to load custom exceptions from a specified package.

View File

@ -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;
}
}

View File

@ -1,8 +0,0 @@
// @expected: TypeMismatchException
public class Example {
public static void testMethod(int x){
}
}

View File

@ -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;
}
}

View File

@ -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{ public class Car{
private int speed; private int speed;
public int getSpeed(){ public int getSpeed(boolean boo){
return speed; return speed;
} }

View File

@ -0,0 +1,13 @@
public class Car{
private int speed;
public int getSpeed(){
return speed;
}
public int test(){
return this.getSpeed();
}
}