diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 0000000..a55e7a1 --- /dev/null +++ b/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/pom.xml b/pom.xml index 9ee63e3..d81162c 100644 --- a/pom.xml +++ b/pom.xml @@ -27,13 +27,22 @@ antlr4-runtime 4.13.1 - org.ow2.asm asm 9.7 - + + com.fasterxml.jackson.core + jackson-databind + 2.16.0 + + + org.assertj + assertj-core + 3.26.0 + test + diff --git a/src/main/java/ast/ClassNode.java b/src/main/java/ast/ClassNode.java index f1f5a4c..26310f8 100644 --- a/src/main/java/ast/ClassNode.java +++ b/src/main/java/ast/ClassNode.java @@ -20,6 +20,8 @@ public class ClassNode implements ASTNode, Visitable { public List members = new ArrayList<>(); public boolean hasConstructor = false; + public ClassNode() {} + public ClassNode(AccessTypeNode accessType, String identifier){ this.accessType = accessType; this.identifier = identifier; diff --git a/src/main/java/ast/expression/ExpressionNode.java b/src/main/java/ast/expression/ExpressionNode.java index e790795..42be180 100644 --- a/src/main/java/ast/expression/ExpressionNode.java +++ b/src/main/java/ast/expression/ExpressionNode.java @@ -1,8 +1,25 @@ package ast.expression; import ast.ASTNode; +import ast.statement.AssignmentStatementNode; +import ast.statement.IfStatementNode; +import ast.statement.VariableDeclarationStatementNode; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonTypeInfo; import visitor.Visitable; +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY) +@JsonSubTypes({ + @JsonSubTypes.Type(value = BinaryExpressionNode.class, name = "Binary"), + @JsonSubTypes.Type(value = This.class, name = "This"), + @JsonSubTypes.Type(value = InstVar.class, name = "InstVar"), + @JsonSubTypes.Type(value = IdentifierExpressionNode.class, name = "Identifier"), + @JsonSubTypes.Type(value = LiteralNode.class, name = "Literal"), + @JsonSubTypes.Type(value = UnaryExpressionNode.class, name = "Unary")} +) + public interface ExpressionNode extends ASTNode, Visitable { } diff --git a/src/main/java/ast/expression/InstVar.java b/src/main/java/ast/expression/InstVar.java index 51c7629..6ffbba3 100644 --- a/src/main/java/ast/expression/InstVar.java +++ b/src/main/java/ast/expression/InstVar.java @@ -10,6 +10,7 @@ public class InstVar implements ExpressionNode, Visitable { public ExpressionNode expression; public TypeNode type; + public InstVar(){} public InstVar(ExpressionNode expression, String identifier) { this.identifier = identifier; diff --git a/src/main/java/ast/LiteralNode.java b/src/main/java/ast/expression/LiteralNode.java similarity index 68% rename from src/main/java/ast/LiteralNode.java rename to src/main/java/ast/expression/LiteralNode.java index 4e7c466..d97f7df 100644 --- a/src/main/java/ast/LiteralNode.java +++ b/src/main/java/ast/expression/LiteralNode.java @@ -1,23 +1,25 @@ -package ast; +package ast.expression; -import ast.expression.ExpressionNode; +import ast.type.TypeNode; import semantic.SemanticVisitor; import typechecker.TypeCheckResult; public class LiteralNode implements ExpressionNode { int value; - private String type; + private TypeNode type; + + public LiteralNode(){} public LiteralNode(int value) { this.value = value; } - public String getType() { + public TypeNode getType() { return type; } - public void setType(String type) { + public void setType(TypeNode type) { this.type = type; } diff --git a/src/main/java/ast/expression/This.java b/src/main/java/ast/expression/This.java new file mode 100644 index 0000000..29fc827 --- /dev/null +++ b/src/main/java/ast/expression/This.java @@ -0,0 +1,26 @@ +package ast.expression; + +import ast.ASTNode; +import ast.type.ReferenceTypeNode; +import ast.type.TypeNode; +import semantic.SemanticVisitor; +import typechecker.TypeCheckResult; + +public class This implements ASTNode, ExpressionNode { + private TypeNode type; + + public This(){} + + public This(String className) { + type = new ReferenceTypeNode(className); + } + + @Override + public TypeCheckResult accept(SemanticVisitor visitor) { + return visitor.analyze(this); + } + + public TypeNode getType() { + return type; + } +} diff --git a/src/main/java/ast/member/FieldNode.java b/src/main/java/ast/member/FieldNode.java index 60c5411..7273f6b 100644 --- a/src/main/java/ast/member/FieldNode.java +++ b/src/main/java/ast/member/FieldNode.java @@ -12,6 +12,8 @@ public class FieldNode implements MemberNode, Visitable { public TypeNode type; public String identifier; + public FieldNode(){} + public FieldNode(AccessTypeNode accessTypeNode, TypeNode type, String name){ this.accessTypeNode = accessTypeNode; this.type = type; diff --git a/src/main/java/ast/member/MemberNode.java b/src/main/java/ast/member/MemberNode.java index f186835..ace0d6d 100644 --- a/src/main/java/ast/member/MemberNode.java +++ b/src/main/java/ast/member/MemberNode.java @@ -1,6 +1,18 @@ package ast.member; import ast.ASTNode; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonTypeInfo; + +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY) +@JsonSubTypes({ + @JsonSubTypes.Type(value = MethodNode.class, name = "Method"), + + @JsonSubTypes.Type(value = FieldNode.class, name = "Field") } +) public interface MemberNode extends ASTNode { + } diff --git a/src/main/java/ast/member/MethodNode.java b/src/main/java/ast/member/MethodNode.java index bd67bc4..f3cba60 100644 --- a/src/main/java/ast/member/MethodNode.java +++ b/src/main/java/ast/member/MethodNode.java @@ -22,6 +22,8 @@ public class MethodNode implements MemberNode, Visitable { public List statements = new ArrayList<>(); + public MethodNode(){} + public MethodNode(AccessTypeNode visibility, TypeNode type, String identifier, ParameterListNode parameters, List statements){ this.visibility = visibility; diff --git a/src/main/java/ast/parameter/ParameterListNode.java b/src/main/java/ast/parameter/ParameterListNode.java index ff1c58d..76a39fb 100644 --- a/src/main/java/ast/parameter/ParameterListNode.java +++ b/src/main/java/ast/parameter/ParameterListNode.java @@ -8,6 +8,8 @@ import java.util.List; public class ParameterListNode implements ASTNode { public List parameters = new ArrayList<>(); + public ParameterListNode() {} + public ParameterListNode(List parameters){ this.parameters = parameters; } diff --git a/src/main/java/ast/parameter/ParameterNode.java b/src/main/java/ast/parameter/ParameterNode.java index f3f5193..176e987 100644 --- a/src/main/java/ast/parameter/ParameterNode.java +++ b/src/main/java/ast/parameter/ParameterNode.java @@ -7,6 +7,8 @@ public class ParameterNode implements ASTNode { public TypeNode type; public String identifier; + public ParameterNode(){} + public ParameterNode(TypeNode type, String identifier) { this.type = type; this.identifier = identifier; diff --git a/src/main/java/ast/statement/AssignmentStatementNode.java b/src/main/java/ast/statement/AssignmentStatementNode.java index d76cc85..abd00a5 100644 --- a/src/main/java/ast/statement/AssignmentStatementNode.java +++ b/src/main/java/ast/statement/AssignmentStatementNode.java @@ -10,7 +10,9 @@ import visitor.Visitable; public class AssignmentStatementNode extends StatementNode implements Visitable { public ExpressionNode expressionLeft; public ExpressionNode expressionRight; - public TypeNode type; +// public TypeNode type; + + public AssignmentStatementNode(){} public AssignmentStatementNode(ExpressionNode expressionLeft, ExpressionNode expressionRight) { this.expressionLeft = expressionLeft; diff --git a/src/main/java/ast/statement/StatementNode.java b/src/main/java/ast/statement/StatementNode.java index eff1804..5a96ee5 100644 --- a/src/main/java/ast/statement/StatementNode.java +++ b/src/main/java/ast/statement/StatementNode.java @@ -1,8 +1,22 @@ package ast.statement; import ast.ASTNode; +import ast.type.BaseTypeNode; +import ast.type.ReferenceTypeNode; import visitor.Visitable; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonTypeInfo; + +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY) +@JsonSubTypes({ + @JsonSubTypes.Type(value = IfStatementNode.class, name = "IF"), + @JsonSubTypes.Type(value = AssignmentStatementNode.class, name = "Assignment"), + @JsonSubTypes.Type(value = VariableDeclarationStatementNode.class, name = "VariableDeclaration") } +) + public abstract class StatementNode implements ASTNode, Visitable { } diff --git a/src/main/java/ast/statement/VariableDeclarationStatementNode.java b/src/main/java/ast/statement/VariableDeclarationStatementNode.java index 4302177..9feb086 100644 --- a/src/main/java/ast/statement/VariableDeclarationStatementNode.java +++ b/src/main/java/ast/statement/VariableDeclarationStatementNode.java @@ -9,6 +9,9 @@ public class VariableDeclarationStatementNode extends StatementNode { public TypeNode type; public String identifier; public ExpressionNode expression; + + public VariableDeclarationStatementNode(){} + public VariableDeclarationStatementNode(TypeNode type, String identifier, ExpressionNode expression) { this.type = type; this.identifier = identifier; diff --git a/src/main/java/ast/type/AccessTypeNode.java b/src/main/java/ast/type/AccessTypeNode.java index ba156c1..4e0db89 100644 --- a/src/main/java/ast/type/AccessTypeNode.java +++ b/src/main/java/ast/type/AccessTypeNode.java @@ -5,6 +5,8 @@ import ast.ASTNode; public class AccessTypeNode implements ASTNode { public EnumAccessTypeNode enumAccessTypeNode; + public AccessTypeNode(){} + public AccessTypeNode(EnumAccessTypeNode enumAccessTypeNode) { this.enumAccessTypeNode = enumAccessTypeNode; } diff --git a/src/main/java/ast/type/BaseTypeNode.java b/src/main/java/ast/type/BaseTypeNode.java index eb9537c..8a9a4a6 100644 --- a/src/main/java/ast/type/BaseTypeNode.java +++ b/src/main/java/ast/type/BaseTypeNode.java @@ -6,6 +6,8 @@ public class BaseTypeNode implements ASTNode, TypeNode { public EnumTypeNode enumType; + public BaseTypeNode(){} + public BaseTypeNode(EnumTypeNode enumType) { this.enumType = enumType; } diff --git a/src/main/java/ast/type/ReferenceTypeNode.java b/src/main/java/ast/type/ReferenceTypeNode.java index 88225f3..91da6bc 100644 --- a/src/main/java/ast/type/ReferenceTypeNode.java +++ b/src/main/java/ast/type/ReferenceTypeNode.java @@ -3,4 +3,34 @@ package ast.type; import ast.ASTNode; public class ReferenceTypeNode implements ASTNode, TypeNode { + + private String identifier; + + public ReferenceTypeNode() {} + + public ReferenceTypeNode(String identifier) { + this.identifier = identifier; + } + + public String getIdentifier() { + return identifier; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + ReferenceTypeNode other = (ReferenceTypeNode) obj; + if (identifier == null) { + if (other.identifier != null) + return false; + } else if (!identifier.equals(other.identifier)) + return false; + return true; + } + } diff --git a/src/main/java/ast/type/This.java b/src/main/java/ast/type/This.java deleted file mode 100644 index 4972ac8..0000000 --- a/src/main/java/ast/type/This.java +++ /dev/null @@ -1,13 +0,0 @@ -package ast.type; - -import ast.ASTNode; -import ast.expression.ExpressionNode; -import semantic.SemanticVisitor; -import typechecker.TypeCheckResult; - -public class This implements ASTNode, ExpressionNode { - @Override - public TypeCheckResult accept(SemanticVisitor visitor) { - return null; - } -} diff --git a/src/main/java/ast/type/TypeNode.java b/src/main/java/ast/type/TypeNode.java index 79be9c9..a855f09 100644 --- a/src/main/java/ast/type/TypeNode.java +++ b/src/main/java/ast/type/TypeNode.java @@ -2,5 +2,17 @@ package ast.type; import ast.ASTNode; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonTypeInfo; + +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY) +@JsonSubTypes({ + @JsonSubTypes.Type(value = BaseTypeNode.class, name = "Base"), + + @JsonSubTypes.Type(value = ReferenceTypeNode.class, name = "Reference") } +) + public interface TypeNode extends ASTNode { } \ No newline at end of file diff --git a/src/main/java/parser/ASTBuilder.java b/src/main/java/parser/ASTBuilder.java index c8dec84..9110f2c 100644 --- a/src/main/java/parser/ASTBuilder.java +++ b/src/main/java/parser/ASTBuilder.java @@ -1,11 +1,7 @@ package parser; import ast.*; -import ast.expression.BinaryExpressionNode; -import ast.expression.ExpressionNode; -import ast.expression.ExpresssionOperator; -import ast.expression.IdentifierExpressionNode; -import ast.expression.UnaryExpressionNode; +import ast.expression.*; import ast.member.FieldNode; import ast.member.MemberNode; import ast.member.MethodNode; @@ -210,7 +206,7 @@ public class ASTBuilder extends SimpleJavaBaseVisitor { int intValue = Integer.parseInt(literalContext.getText()); LiteralNode literalNode = new LiteralNode(intValue); - literalNode.setType("int"); + literalNode.setType(new BaseTypeNode(EnumTypeNode.INT)); return literalNode; } catch (NumberFormatException ignored) {} diff --git a/src/main/java/semantic/SemanticAnalyzer.java b/src/main/java/semantic/SemanticAnalyzer.java index ab1051b..2d95119 100644 --- a/src/main/java/semantic/SemanticAnalyzer.java +++ b/src/main/java/semantic/SemanticAnalyzer.java @@ -10,6 +10,9 @@ import ast.member.MethodNode; import ast.parameter.ParameterListNode; import ast.parameter.ParameterNode; import ast.statement.*; +import ast.type.ReferenceTypeNode; +import ast.expression.This; + import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -17,8 +20,8 @@ import java.util.Objects; import ast.type.BaseTypeNode; import ast.type.EnumTypeNode; -import ast.type.This; import ast.type.TypeNode; +import semantic.context.Context; import semantic.exeptions.AlreadyDeclearedException; import semantic.exeptions.NotDeclearedException; import semantic.exeptions.TypeMismatchException; @@ -30,6 +33,7 @@ public class SemanticAnalyzer implements SemanticVisitor { public static ArrayList errors = new ArrayList<>(); + private Context context; private static Scope currentScope; private static ClassNode currentClass; @@ -60,6 +64,7 @@ public class SemanticAnalyzer implements SemanticVisitor { var valid = true; currentScope = new Scope(); + context = new Context(node); List classes = node.classes; for (ClassNode classNode : classes) { @@ -74,7 +79,7 @@ public class SemanticAnalyzer implements SemanticVisitor { var valid = true; currentClass = classNode; - + currentFields.clear(); List members = classNode.members; for (MemberNode memberNode : members) { if (memberNode instanceof FieldNode fieldNode) { @@ -238,23 +243,38 @@ public class SemanticAnalyzer implements SemanticVisitor { @Override public TypeCheckResult analyze(LiteralNode toCheck) { - return new TypeCheckResult(true, new BaseTypeNode(EnumTypeNode.INT)); + return new TypeCheckResult(true, toCheck.getType()); } @Override public TypeCheckResult analyze(InstVar toCheck) { boolean valid = true; - if(toCheck.expression instanceof This){ - if(currentFields.get(toCheck.identifier) == null){ - errors.add(new NotDeclearedException("Not declared " + toCheck.identifier + " in this scope")); - valid = false; + var result = toCheck.expression.accept(this); + + if(result.getType() instanceof BaseTypeNode){ + throw new RuntimeException("BaseType has no Methods or Fields"); + } else { + //Get typ of Field + + var type = (ReferenceTypeNode)result.getType(); + var classContext = context.getClass(type.getIdentifier()); + + if(classContext == null){ + errors.add(new NotDeclearedException("Not declared " + type.getIdentifier() + " in this scope")); + return new TypeCheckResult(false, null); } else { - TypeNode typeNode = currentFields.get(toCheck.identifier); - return new TypeCheckResult(valid, typeNode); + var field = classContext.getField(toCheck.identifier); + + return new TypeCheckResult(valid, field.getType()); } } - return new TypeCheckResult(valid, null); + + } + + @Override + public TypeCheckResult analyze(This toCheck) { + return new TypeCheckResult(true, toCheck.getType()); } } \ No newline at end of file diff --git a/src/main/java/semantic/SemanticVisitor.java b/src/main/java/semantic/SemanticVisitor.java index fd69518..b66ea75 100644 --- a/src/main/java/semantic/SemanticVisitor.java +++ b/src/main/java/semantic/SemanticVisitor.java @@ -2,7 +2,7 @@ package semantic; import ast.ClassNode; -import ast.LiteralNode; +import ast.expression.LiteralNode; import ast.ProgramNode; import ast.expression.BinaryExpressionNode; import ast.expression.IdentifierExpressionNode; @@ -11,6 +11,7 @@ import ast.expression.UnaryExpressionNode; import ast.member.FieldNode; import ast.member.MethodNode; import ast.statement.*; +import ast.expression.This; import typechecker.TypeCheckResult; public interface SemanticVisitor { @@ -42,4 +43,6 @@ public interface SemanticVisitor { TypeCheckResult analyze(LiteralNode toCheck); TypeCheckResult analyze(InstVar toCheck); + + TypeCheckResult analyze(This toCheck); } \ No newline at end of file diff --git a/src/main/java/semantic/context/ClassContext.java b/src/main/java/semantic/context/ClassContext.java new file mode 100644 index 0000000..982866f --- /dev/null +++ b/src/main/java/semantic/context/ClassContext.java @@ -0,0 +1,27 @@ +package semantic.context; + +import ast.ClassNode; +import ast.member.FieldNode; +import java.util.HashMap; + +public class ClassContext { + + private HashMap fields; + + public ClassContext(ClassNode classNode) { + + fields = new HashMap<>(); + + classNode.members.forEach(member -> { + if(member instanceof FieldNode fieldNode) { + fields.put(fieldNode.identifier, new FieldContext(fieldNode)); + } + }); + + } + + public FieldContext getField(String name) { + return fields.get(name); + } + +} diff --git a/src/main/java/semantic/context/Context.java b/src/main/java/semantic/context/Context.java new file mode 100644 index 0000000..7006e65 --- /dev/null +++ b/src/main/java/semantic/context/Context.java @@ -0,0 +1,25 @@ +package semantic.context; + +import ast.ClassNode; +import ast.ProgramNode; +import java.util.HashMap; + +public class Context { + + private HashMap classes; + + public Context(ProgramNode programNode) { + classes = new HashMap<>(); + + programNode.classes.forEach(classNode -> { + ClassContext classContext = new ClassContext(classNode); + classes.put(classNode.identifier, classContext); + }); + + } + + public ClassContext getClass(String identifier) { + return classes.get(identifier); + } + +} diff --git a/src/main/java/semantic/context/FieldContext.java b/src/main/java/semantic/context/FieldContext.java new file mode 100644 index 0000000..447aa4e --- /dev/null +++ b/src/main/java/semantic/context/FieldContext.java @@ -0,0 +1,22 @@ +package semantic.context; + +import ast.member.FieldNode; +import ast.type.AccessTypeNode; +import ast.type.EnumAccessTypeNode; +import ast.type.TypeNode; + +public class FieldContext { + + private AccessTypeNode accessModifier; + private TypeNode type; + + public FieldContext(FieldNode field) { + accessModifier = field.accessTypeNode; + type = field.type; + } + + public TypeNode getType() { + return type; + } + +} diff --git a/src/test/java/semantic/Mocker.java b/src/test/java/semantic/Mocker.java index 433d0ab..4c303d8 100644 --- a/src/test/java/semantic/Mocker.java +++ b/src/test/java/semantic/Mocker.java @@ -1,7 +1,7 @@ package semantic; import ast.ClassNode; -import ast.LiteralNode; +import ast.expression.LiteralNode; import ast.ProgramNode; import ast.expression.*; import ast.member.FieldNode; @@ -39,16 +39,14 @@ public class Mocker { List statementNodeList = new ArrayList(); - ExpressionNode expressionNodeLeft = new InstVar(new This(), "objectVar"); + ExpressionNode expressionNodeLeft = new InstVar(new This("testClass"), "objectVar"); - ExpressionNode expressionNodeRight = new LiteralNode(1); + LiteralNode expressionNodeRight = new LiteralNode(); + expressionNodeRight.setType(new BaseTypeNode(EnumTypeNode.INT)); StatementNode statementNode1 = new AssignmentStatementNode(expressionNodeLeft, expressionNodeRight); 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); @@ -76,5 +74,4 @@ public class Mocker { return programNode; } - } diff --git a/src/test/java/semantic/SemanticTest.java b/src/test/java/semantic/SemanticTest.java index c5990de..71604ee 100644 --- a/src/test/java/semantic/SemanticTest.java +++ b/src/test/java/semantic/SemanticTest.java @@ -2,20 +2,19 @@ package semantic; import ast.*; -import ast.member.FieldNode; -import ast.member.MemberNode; -import ast.type.AccessTypeNode; -import ast.type.BaseTypeNode; -import ast.type.EnumAccessTypeNode; -import ast.type.EnumTypeNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.assertj.core.api.MatcherAssert; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import semantic.exeptions.AlreadyDeclearedException; +import semantic.exeptions.TypeMismatchException; -import java.util.ArrayList; -import java.util.List; +import java.io.File; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; public class SemanticTest { @@ -25,7 +24,7 @@ public class SemanticTest { } @Test - public void alreadyDeclaredLocalFieldVar(){ + public void alreadyDeclaredLocalFieldVar() { //Arrange @@ -44,7 +43,7 @@ public class SemanticTest { } @Test - public void typeMismatch(){ + public void alreadyDecleared() { //Arrange @@ -57,13 +56,13 @@ public class SemanticTest { //Assert assertEquals(1, SemanticAnalyzer.errors.size()); - assertEquals(true, SemanticAnalyzer.errors.get(0) instanceof AlreadyDeclearedException); - assertEquals(null, typedAst); + assertInstanceOf(AlreadyDeclearedException.class, SemanticAnalyzer.errors.getFirst()); + assertNull(typedAst); } @Test - public void shouldWorkWithNoError(){ + public void shouldWorkWithNoError() { //Arrange @@ -80,4 +79,85 @@ public class SemanticTest { } + @Test + public void refTypeCorrect() { + + //Arrange + + ObjectMapper objectMapper = new ObjectMapper(); + ProgramNode programNode = null; + try{ + programNode = objectMapper.readValue(new File("src/test/resources/semantic/correctRefType.json"), ProgramNode.class); + } catch (Exception e) { + e.printStackTrace(); + } + + //Act + + ASTNode typedAst = SemanticAnalyzer.generateTast(programNode); + + //Assert + + assertEquals(0, SemanticAnalyzer.errors.size()); + assertEquals(programNode, typedAst); + + } + + @Test + public void jsonWriteTest() { + + ObjectMapper objectMapper = new ObjectMapper(); + + //Arrange + + ProgramNode programNode = Mocker.mockCorrectProgrammNode(); + try{ + objectMapper.writeValue(new File("src/test/resources/semantic/test.json"), programNode); + } catch (Exception e) { + e.printStackTrace(); + } + + } + + @Test + public void jsonReadTest() { + + ObjectMapper objectMapper = new ObjectMapper(); + + ProgramNode programNode1 = null; + try{ + programNode1 = objectMapper.readValue(new File("src/test/resources/semantic/test.json"), ProgramNode.class); + } catch (Exception e) { + e.printStackTrace(); + } + + ProgramNode programNode2 = Mocker.mockCorrectProgrammNode(); + + } + + @Test + public void typeMismatch() { + + //Arrange + + ObjectMapper objectMapper = new ObjectMapper(); + ProgramNode programNode = null; + try{ + programNode = objectMapper.readValue(new File("src/test/resources/semantic/refTypeMismatch.json"), ProgramNode.class); + } catch (Exception e) { + e.printStackTrace(); + } + + //Act + + ASTNode typedAst = SemanticAnalyzer.generateTast(programNode); + + //Assert + + assertEquals(1, SemanticAnalyzer.errors.size()); + assertInstanceOf(TypeMismatchException.class, SemanticAnalyzer.errors.getFirst()); + assertNull(typedAst); + + } + } diff --git a/src/test/resources/semantic/correctRefType.json b/src/test/resources/semantic/correctRefType.json new file mode 100644 index 0000000..7e67bbc --- /dev/null +++ b/src/test/resources/semantic/correctRefType.json @@ -0,0 +1,70 @@ +{ + "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 new file mode 100644 index 0000000..e5ebcd3 --- /dev/null +++ b/src/test/resources/semantic/refTypeMismatch.json @@ -0,0 +1,133 @@ +{ + "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 new file mode 100644 index 0000000..7acc30f --- /dev/null +++ b/src/test/resources/semantic/test.json @@ -0,0 +1 @@ +{"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