Added typecheck for Assignment
Some checks failed
Gitea Actions Demo / Explore-Gitea-Actions (push) Has been cancelled
Some checks failed
Gitea Actions Demo / Explore-Gitea-Actions (push) Has been cancelled
This commit is contained in:
parent
c483babaf5
commit
22a30d5956
@ -24,6 +24,6 @@ public class LiteralNode implements ExpressionNode {
|
||||
|
||||
@Override
|
||||
public TypeCheckResult accept(SemanticVisitor visitor) {
|
||||
return null;
|
||||
return visitor.analyze(this);
|
||||
}
|
||||
}
|
||||
|
@ -10,4 +10,17 @@ public class BaseTypeNode implements ASTNode, TypeNode {
|
||||
this.enumType = enumType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
BaseTypeNode other = (BaseTypeNode) obj;
|
||||
if (enumType != other.enumType)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
6
src/main/java/ast/type/This.java
Normal file
6
src/main/java/ast/type/This.java
Normal file
@ -0,0 +1,6 @@
|
||||
package ast.type;
|
||||
|
||||
import ast.ASTNode;
|
||||
|
||||
public class This implements ASTNode, TypeNode{
|
||||
}
|
@ -3,6 +3,7 @@ package semantic;
|
||||
|
||||
import ast.*;
|
||||
import ast.expression.BinaryExpressionNode;
|
||||
import ast.expression.ExpressionNode;
|
||||
import ast.expression.IdentifierExpressionNode;
|
||||
import ast.expression.UnaryExpressionNode;
|
||||
import ast.member.ConstructorNode;
|
||||
@ -14,15 +15,23 @@ import ast.parameter.ParameterListNode;
|
||||
import ast.parameter.ParameterNode;
|
||||
import ast.statement.*;
|
||||
|
||||
import java.beans.Expression;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import ast.type.BaseTypeNode;
|
||||
import ast.type.EnumTypeNode;
|
||||
import ast.type.This;
|
||||
import ast.type.TypeNode;
|
||||
import semantic.exeptions.AlreadyDeclearedException;
|
||||
import semantic.exeptions.TypeMismatchException;
|
||||
import typechecker.TypeCheckResult;
|
||||
|
||||
public class SemanticAnalyzer implements SemanticVisitor {
|
||||
|
||||
private static ArrayList<String> currentFields = new ArrayList<>();
|
||||
private static HashMap<String, TypeNode> currentFields = new HashMap<>();
|
||||
|
||||
public static ArrayList<Exception> errors = new ArrayList<>();
|
||||
|
||||
@ -134,11 +143,11 @@ public class SemanticAnalyzer implements SemanticVisitor {
|
||||
|
||||
@Override
|
||||
public TypeCheckResult analyze(FieldNode toCheck) {
|
||||
if (currentFields.contains(toCheck.identifier)) {
|
||||
if (currentFields.get(toCheck.identifier) != null) {
|
||||
errors.add(new AlreadyDeclearedException("Already declared " + toCheck.identifier));
|
||||
return new TypeCheckResult(false, null);
|
||||
} else {
|
||||
currentFields.add(toCheck.identifier);
|
||||
currentFields.put(toCheck.identifier, toCheck.type);
|
||||
}
|
||||
return new TypeCheckResult(true, null);
|
||||
}
|
||||
@ -155,12 +164,39 @@ public class SemanticAnalyzer implements SemanticVisitor {
|
||||
@Override
|
||||
public TypeCheckResult analyze(BinaryExpressionNode toCheck) {
|
||||
boolean valid = true;
|
||||
ExpressionNode left = toCheck.left;
|
||||
var resultLeft = left.accept(this);
|
||||
ExpressionNode right = toCheck.right;
|
||||
var resultRight = right.accept(this);
|
||||
|
||||
switch (toCheck.operator) {
|
||||
case ASSIGNMENT:
|
||||
if(Objects.equals(resultRight.getType(), resultLeft.getType())){
|
||||
System.out.println("Correct Type");
|
||||
} else {
|
||||
valid = false;
|
||||
errors.add(new TypeMismatchException("Type Mismatch " + resultLeft.getType() + " and " + resultRight.getType()));
|
||||
}
|
||||
break;
|
||||
case DOT:
|
||||
return new TypeCheckResult(true, resultRight.getType());
|
||||
default:
|
||||
throw new RuntimeException("Unexpected operator: " + toCheck.operator);
|
||||
}
|
||||
|
||||
return new TypeCheckResult(valid, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeCheckResult analyze(IdentifierExpressionNode toCheck) {
|
||||
return null;
|
||||
if(toCheck.name == "this"){
|
||||
return new TypeCheckResult(true, new This());
|
||||
} else if (currentFields.get(toCheck.name) == null) {
|
||||
errors.add(new AlreadyDeclearedException("Not declared " + toCheck.name + " in this scope"));
|
||||
return new TypeCheckResult(false, null);
|
||||
} else {
|
||||
return new TypeCheckResult(false, currentFields.get(toCheck.name));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -194,4 +230,9 @@ public class SemanticAnalyzer implements SemanticVisitor {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeCheckResult analyze(LiteralNode toCheck) {
|
||||
return new TypeCheckResult(true, new BaseTypeNode(EnumTypeNode.INT));
|
||||
}
|
||||
|
||||
}
|
@ -2,6 +2,7 @@ package semantic;
|
||||
|
||||
|
||||
import ast.ClassNode;
|
||||
import ast.LiteralNode;
|
||||
import ast.ProgramNode;
|
||||
import ast.expression.BinaryExpressionNode;
|
||||
import ast.expression.IdentifierExpressionNode;
|
||||
@ -36,4 +37,6 @@ public interface SemanticVisitor {
|
||||
TypeCheckResult analyze(ReturnStatementNode toCheck);
|
||||
|
||||
TypeCheckResult analyze(WhileStatementNode toCheck);
|
||||
|
||||
TypeCheckResult analyze(LiteralNode toCheck);
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
package semantic.exeptions;
|
||||
|
||||
public class TypeMismatchException extends RuntimeException {
|
||||
|
||||
public TypeMismatchException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
}
|
91
src/test/java/semantic/Mocker.java
Normal file
91
src/test/java/semantic/Mocker.java
Normal file
@ -0,0 +1,91 @@
|
||||
package semantic;
|
||||
|
||||
import ast.ClassNode;
|
||||
import ast.LiteralNode;
|
||||
import ast.ProgramNode;
|
||||
import ast.expression.BinaryExpressionNode;
|
||||
import ast.expression.ExpressionNode;
|
||||
import ast.expression.ExpresssionOperator;
|
||||
import ast.expression.IdentifierExpressionNode;
|
||||
import ast.member.FieldNode;
|
||||
import ast.member.MemberNode;
|
||||
import ast.member.MethodNode;
|
||||
import ast.parameter.ParameterListNode;
|
||||
import ast.parameter.ParameterNode;
|
||||
import ast.statement.AssignmentStatementNode;
|
||||
import ast.statement.StatementNode;
|
||||
import ast.statement.VariableDeclarationStatementNode;
|
||||
import ast.type.AccessTypeNode;
|
||||
import ast.type.BaseTypeNode;
|
||||
import ast.type.EnumAccessTypeNode;
|
||||
import ast.type.EnumTypeNode;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class Mocker {
|
||||
|
||||
public static ProgramNode mockCorrectProgrammNode(){
|
||||
|
||||
ProgramNode programNode = new ProgramNode();
|
||||
List<ClassNode> classList = new ArrayList<ClassNode>();
|
||||
AccessTypeNode accessTypeNode = new AccessTypeNode(EnumAccessTypeNode.PUBLIC);
|
||||
ClassNode classNode = new ClassNode(accessTypeNode, "testClass");
|
||||
|
||||
MemberNode memberNode1 = new FieldNode(accessTypeNode, new BaseTypeNode(EnumTypeNode.INT), "testVar1");
|
||||
classNode.members.add(memberNode1);
|
||||
|
||||
MemberNode memberNode2 = new FieldNode(accessTypeNode, new BaseTypeNode(EnumTypeNode.INT), "objectVar");
|
||||
classNode.members.add(memberNode2);
|
||||
|
||||
List<ParameterNode> parameterNodeList = new ArrayList<ParameterNode>();
|
||||
ParameterNode parameterNode1 = new ParameterNode(new BaseTypeNode(EnumTypeNode.INT), "param1");
|
||||
parameterNodeList.add(parameterNode1);
|
||||
ParameterListNode parameterListNode = new ParameterListNode(parameterNodeList);
|
||||
|
||||
List<StatementNode> statementNodeList = new ArrayList<StatementNode>();
|
||||
|
||||
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);
|
||||
|
||||
StatementNode statementNode1 = new AssignmentStatementNode(expressionNode);
|
||||
statementNodeList.add(statementNode1);
|
||||
|
||||
StatementNode statementNode2 = new VariableDeclarationStatementNode(new BaseTypeNode(EnumTypeNode.CHAR), "objectVar", new LiteralNode(1));
|
||||
statementNodeList.add(statementNode2);
|
||||
|
||||
MemberNode memberNode3 = new MethodNode(accessTypeNode, new BaseTypeNode(EnumTypeNode.INT), "testVar2",parameterListNode, statementNodeList );
|
||||
classNode.members.add(memberNode3);
|
||||
|
||||
classList.add(classNode);
|
||||
programNode.classes = classList;
|
||||
|
||||
return programNode;
|
||||
|
||||
}
|
||||
|
||||
public static ProgramNode mockFieldNodeAlreadyDeclaredProgrammNode(){
|
||||
ProgramNode programNode = new ProgramNode();
|
||||
List<ClassNode> classList = new ArrayList<ClassNode>();
|
||||
AccessTypeNode accessTypeNode = new AccessTypeNode(EnumAccessTypeNode.PUBLIC);
|
||||
ClassNode classNode = new ClassNode(accessTypeNode, "testClass");
|
||||
|
||||
MemberNode memberNode1 = new FieldNode(accessTypeNode, new BaseTypeNode(EnumTypeNode.INT), "testVar");
|
||||
classNode.members.add(memberNode1);
|
||||
|
||||
MemberNode memberNode2 = new FieldNode(accessTypeNode, new BaseTypeNode(EnumTypeNode.INT), "testVar");
|
||||
classNode.members.add(memberNode2);
|
||||
|
||||
classList.add(classNode);
|
||||
programNode.classes = classList;
|
||||
|
||||
return programNode;
|
||||
}
|
||||
|
||||
}
|
@ -2,17 +2,8 @@ package semantic;
|
||||
|
||||
|
||||
import ast.*;
|
||||
import ast.expression.BinaryExpressionNode;
|
||||
import ast.expression.ExpressionNode;
|
||||
import ast.expression.ExpresssionOperator;
|
||||
import ast.expression.IdentifierExpressionNode;
|
||||
import ast.member.FieldNode;
|
||||
import ast.member.MemberNode;
|
||||
import ast.member.MethodNode;
|
||||
import ast.parameter.ParameterListNode;
|
||||
import ast.parameter.ParameterNode;
|
||||
import ast.statement.AssignmentStatementNode;
|
||||
import ast.statement.StatementNode;
|
||||
import ast.type.AccessTypeNode;
|
||||
import ast.type.BaseTypeNode;
|
||||
import ast.type.EnumAccessTypeNode;
|
||||
@ -36,22 +27,35 @@ public class SemanticTest {
|
||||
@Test
|
||||
public void alreadyDeclaredLocalFieldVar(){
|
||||
|
||||
ProgramNode programNode = new ProgramNode();
|
||||
List<ClassNode> classList = new ArrayList<ClassNode>();
|
||||
AccessTypeNode accessTypeNode = new AccessTypeNode(EnumAccessTypeNode.PUBLIC);
|
||||
ClassNode classNode = new ClassNode(accessTypeNode, "testClass");
|
||||
//Arrange
|
||||
|
||||
MemberNode memberNode1 = new FieldNode(accessTypeNode, new BaseTypeNode(EnumTypeNode.INT), "testVar");
|
||||
classNode.members.add(memberNode1);
|
||||
ProgramNode programNode = Mocker.mockFieldNodeAlreadyDeclaredProgrammNode();
|
||||
|
||||
MemberNode memberNode2 = new FieldNode(accessTypeNode, new BaseTypeNode(EnumTypeNode.INT), "testVar");
|
||||
classNode.members.add(memberNode2);
|
||||
|
||||
classList.add(classNode);
|
||||
programNode.classes = classList;
|
||||
//Act
|
||||
|
||||
ASTNode typedAst = SemanticAnalyzer.generateTast(programNode);
|
||||
|
||||
//Assert
|
||||
|
||||
assertEquals(1, SemanticAnalyzer.errors.size());
|
||||
assertEquals(true, SemanticAnalyzer.errors.get(0) instanceof AlreadyDeclearedException);
|
||||
assertEquals(null, typedAst);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void typeMismatch(){
|
||||
|
||||
//Arrange
|
||||
|
||||
ProgramNode programNode = Mocker.mockFieldNodeAlreadyDeclaredProgrammNode();
|
||||
|
||||
//Act
|
||||
|
||||
ASTNode typedAst = SemanticAnalyzer.generateTast(programNode);
|
||||
|
||||
//Assert
|
||||
|
||||
assertEquals(1, SemanticAnalyzer.errors.size());
|
||||
assertEquals(true, SemanticAnalyzer.errors.get(0) instanceof AlreadyDeclearedException);
|
||||
assertEquals(null, typedAst);
|
||||
@ -61,44 +65,16 @@ public class SemanticTest {
|
||||
@Test
|
||||
public void shouldWorkWithNoError(){
|
||||
|
||||
ProgramNode programNode = new ProgramNode();
|
||||
List<ClassNode> classList = new ArrayList<ClassNode>();
|
||||
AccessTypeNode accessTypeNode = new AccessTypeNode(EnumAccessTypeNode.PUBLIC);
|
||||
ClassNode classNode = new ClassNode(accessTypeNode, "testClass");
|
||||
//Arrange
|
||||
|
||||
MemberNode memberNode1 = new FieldNode(accessTypeNode, new BaseTypeNode(EnumTypeNode.INT), "testVar1");
|
||||
classNode.members.add(memberNode1);
|
||||
ProgramNode programNode = Mocker.mockCorrectProgrammNode();
|
||||
|
||||
MemberNode memberNode2 = new FieldNode(accessTypeNode, new BaseTypeNode(EnumTypeNode.INT), "testVar2");
|
||||
classNode.members.add(memberNode2);
|
||||
|
||||
List<ParameterNode> parameterNodeList = new ArrayList<ParameterNode>();
|
||||
ParameterNode parameterNode1 = new ParameterNode(new BaseTypeNode(EnumTypeNode.INT), "param1");
|
||||
parameterNodeList.add(parameterNode1);
|
||||
ParameterListNode parameterListNode = new ParameterListNode(parameterNodeList);
|
||||
|
||||
List<StatementNode> statementNodeList = new ArrayList<StatementNode>();
|
||||
|
||||
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);
|
||||
|
||||
StatementNode statementNode1 = new AssignmentStatementNode(expressionNode);
|
||||
statementNodeList.add(statementNode1);
|
||||
|
||||
MemberNode memberNode3 = new MethodNode(accessTypeNode, new BaseTypeNode(EnumTypeNode.INT), "testVar2",parameterListNode, statementNodeList );
|
||||
classNode.members.add(memberNode3);
|
||||
|
||||
classList.add(classNode);
|
||||
programNode.classes = classList;
|
||||
//Act
|
||||
|
||||
ASTNode typedAst = SemanticAnalyzer.generateTast(programNode);
|
||||
|
||||
//Assert
|
||||
|
||||
assertEquals(0, SemanticAnalyzer.errors.size());
|
||||
assertEquals(programNode, typedAst);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user