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/ExpresssionOperator.java b/src/main/java/ast/expression/ExpresssionOperator.java
index b1f62a3..42bc137 100644
--- a/src/main/java/ast/expression/ExpresssionOperator.java
+++ b/src/main/java/ast/expression/ExpresssionOperator.java
@@ -1,13 +1,13 @@
package ast.expression;
public enum ExpresssionOperator {
- DOT, // .
+ DOT, // . NICHT MEHR GEBRAUCHT
PLUS, // +
MINUS, // -
MULTIPLY, // *
DIVIDE, // /
NOT, // !
- ASSIGNMENT, // =
+ ASSIGNMENT, // = (NICHT MEHR GEBRAUCHT ??)
EQUALS, // ==
UNEQUALS, // !=
ERROR //TODO: Remove This
diff --git a/src/main/java/ast/expression/InstVar.java b/src/main/java/ast/expression/InstVar.java
new file mode 100644
index 0000000..6ffbba3
--- /dev/null
+++ b/src/main/java/ast/expression/InstVar.java
@@ -0,0 +1,24 @@
+package ast.expression;
+
+import ast.type.TypeNode;
+import semantic.SemanticVisitor;
+import typechecker.TypeCheckResult;
+import visitor.Visitable;
+
+public class InstVar implements ExpressionNode, Visitable {
+ public String identifier;
+ public ExpressionNode expression;
+ public TypeNode type;
+
+ public InstVar(){}
+
+ public InstVar(ExpressionNode expression, String identifier) {
+ this.identifier = identifier;
+ this.expression = expression;
+ }
+
+ @Override
+ public TypeCheckResult accept(SemanticVisitor visitor) {
+ return visitor.analyze(this);
+ }
+}
diff --git a/src/main/java/ast/LiteralNode.java b/src/main/java/ast/expression/LiteralNode.java
similarity index 61%
rename from src/main/java/ast/LiteralNode.java
rename to src/main/java/ast/expression/LiteralNode.java
index 3873465..d97f7df 100644
--- a/src/main/java/ast/LiteralNode.java
+++ b/src/main/java/ast/expression/LiteralNode.java
@@ -1,29 +1,31 @@
-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;
}
@Override
public TypeCheckResult accept(SemanticVisitor visitor) {
- return null;
+ return visitor.analyze(this);
}
}
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 f9fd38e..abd00a5 100644
--- a/src/main/java/ast/statement/AssignmentStatementNode.java
+++ b/src/main/java/ast/statement/AssignmentStatementNode.java
@@ -1,15 +1,22 @@
package ast.statement;
import ast.expression.BinaryExpressionNode;
+import ast.expression.ExpressionNode;
+import ast.type.TypeNode;
import semantic.SemanticVisitor;
import typechecker.TypeCheckResult;
import visitor.Visitable;
public class AssignmentStatementNode extends StatementNode implements Visitable {
- public BinaryExpressionNode expression;
+ public ExpressionNode expressionLeft;
+ public ExpressionNode expressionRight;
+// public TypeNode type;
- public AssignmentStatementNode(BinaryExpressionNode expression) {
- this.expression = expression;
+ public AssignmentStatementNode(){}
+
+ public AssignmentStatementNode(ExpressionNode expressionLeft, ExpressionNode expressionRight) {
+ this.expressionLeft = expressionLeft;
+ this.expressionRight = expressionRight;
}
@Override
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 2d871ab..8a9a4a6 100644
--- a/src/main/java/ast/type/BaseTypeNode.java
+++ b/src/main/java/ast/type/BaseTypeNode.java
@@ -6,8 +6,23 @@ public class BaseTypeNode implements ASTNode, TypeNode {
public EnumTypeNode enumType;
+ public BaseTypeNode(){}
+
public BaseTypeNode(EnumTypeNode enumType) {
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;
+ }
}
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/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/classFileOutput/Example.class b/src/main/java/classFileOutput/Example.class
index 522ae9e..e69de29 100644
Binary files a/src/main/java/classFileOutput/Example.class and b/src/main/java/classFileOutput/Example.class differ
diff --git a/src/main/java/parser/ASTBuilder.java b/src/main/java/parser/ASTBuilder.java
index 0f3b09c..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;
@@ -138,9 +134,8 @@ public class ASTBuilder extends SimpleJavaBaseVisitor {
@Override
public ASTNode visitAssignmentStatement(SimpleJavaParser.AssignmentStatementContext ctx) {
-
- BinaryExpressionNode expression = (BinaryExpressionNode) visit(ctx.expression());
- return new AssignmentStatementNode(expression);
+ ExpressionNode expression = (ExpressionNode) visit(ctx.expression());
+ return null;
}
@Override
@@ -211,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 9ccfe98..2d95119 100644
--- a/src/main/java/semantic/SemanticAnalyzer.java
+++ b/src/main/java/semantic/SemanticAnalyzer.java
@@ -2,10 +2,7 @@ package semantic;
import ast.*;
-import ast.expression.BinaryExpressionNode;
-import ast.expression.IdentifierExpressionNode;
-import ast.expression.UnaryExpressionNode;
-import ast.member.ConstructorNode;
+import ast.expression.*;
import ast.member.FieldNode;
import ast.member.MemberNode;
@@ -13,19 +10,30 @@ 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;
+import java.util.Objects;
+import ast.type.BaseTypeNode;
+import ast.type.EnumTypeNode;
+import ast.type.TypeNode;
+import semantic.context.Context;
import semantic.exeptions.AlreadyDeclearedException;
+import semantic.exeptions.NotDeclearedException;
+import semantic.exeptions.TypeMismatchException;
import typechecker.TypeCheckResult;
public class SemanticAnalyzer implements SemanticVisitor {
- private static ArrayList currentFields = new ArrayList<>();
+ private static HashMap currentFields = new HashMap<>();
public static ArrayList errors = new ArrayList<>();
+ private Context context;
private static Scope currentScope;
private static ClassNode currentClass;
@@ -56,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) {
@@ -70,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) {
@@ -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);
}
@@ -146,21 +155,59 @@ public class SemanticAnalyzer implements SemanticVisitor {
@Override
public TypeCheckResult analyze(AssignmentStatementNode assignmentStatementNode) {
boolean valid = true;
- BinaryExpressionNode binaryExpressionNode = assignmentStatementNode.expression;
- var result = binaryExpressionNode.accept(this);
- valid = valid && result.isValid();
+ ExpressionNode expressionNodeLeft = assignmentStatementNode.expressionLeft;
+ var resultLeft = expressionNodeLeft.accept(this);
+ valid = valid && resultLeft.isValid();
+ ExpressionNode expressionNodeRight = assignmentStatementNode.expressionRight;
+ var resultRight = expressionNodeRight.accept(this);
+ valid = valid && resultRight.isValid();
+
+ if(Objects.equals(resultLeft.getType(), resultRight.getType())){
+ System.out.println("SAME TYPE");
+ } else {
+ errors.add(new TypeMismatchException("Type mismatch"));
+ valid = false;
+ }
+
return new TypeCheckResult(valid, null);
}
@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, null);
+ } 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 +241,40 @@ public class SemanticAnalyzer implements SemanticVisitor {
return null;
}
+ @Override
+ public TypeCheckResult analyze(LiteralNode toCheck) {
+ return new TypeCheckResult(true, toCheck.getType());
+ }
+
+ @Override
+ public TypeCheckResult analyze(InstVar toCheck) {
+ boolean valid = true;
+
+ 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 {
+ var field = classContext.getField(toCheck.identifier);
+
+ return new TypeCheckResult(valid, field.getType());
+ }
+ }
+
+ }
+
+ @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 66db83e..b66ea75 100644
--- a/src/main/java/semantic/SemanticVisitor.java
+++ b/src/main/java/semantic/SemanticVisitor.java
@@ -2,13 +2,16 @@ package semantic;
import ast.ClassNode;
+import ast.expression.LiteralNode;
import ast.ProgramNode;
import ast.expression.BinaryExpressionNode;
import ast.expression.IdentifierExpressionNode;
+import ast.expression.InstVar;
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 {
@@ -36,4 +39,10 @@ public interface SemanticVisitor {
TypeCheckResult analyze(ReturnStatementNode toCheck);
TypeCheckResult analyze(WhileStatementNode toCheck);
+
+ 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/main/java/semantic/exeptions/NotDeclearedException.java b/src/main/java/semantic/exeptions/NotDeclearedException.java
new file mode 100644
index 0000000..aa223a0
--- /dev/null
+++ b/src/main/java/semantic/exeptions/NotDeclearedException.java
@@ -0,0 +1,9 @@
+package semantic.exeptions;
+
+public class NotDeclearedException extends RuntimeException {
+
+ public NotDeclearedException(String message) {
+ super(message);
+ }
+
+}
diff --git a/src/main/java/semantic/exeptions/TypeMismatchException.java b/src/main/java/semantic/exeptions/TypeMismatchException.java
new file mode 100644
index 0000000..93fb62b
--- /dev/null
+++ b/src/main/java/semantic/exeptions/TypeMismatchException.java
@@ -0,0 +1,9 @@
+package semantic.exeptions;
+
+public class TypeMismatchException extends RuntimeException {
+
+ public TypeMismatchException(String message) {
+ super(message);
+ }
+
+}
diff --git a/src/test/java/semantic/Mocker.java b/src/test/java/semantic/Mocker.java
new file mode 100644
index 0000000..4c303d8
--- /dev/null
+++ b/src/test/java/semantic/Mocker.java
@@ -0,0 +1,77 @@
+package semantic;
+
+import ast.ClassNode;
+import ast.expression.LiteralNode;
+import ast.ProgramNode;
+import ast.expression.*;
+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.*;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class Mocker {
+
+ public static ProgramNode mockCorrectProgrammNode(){
+
+ ProgramNode programNode = new ProgramNode();
+ List classList = new ArrayList();
+ 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 parameterNodeList = new ArrayList();
+ ParameterNode parameterNode1 = new ParameterNode(new BaseTypeNode(EnumTypeNode.INT), "param1");
+ parameterNodeList.add(parameterNode1);
+ ParameterListNode parameterListNode = new ParameterListNode(parameterNodeList);
+
+ List statementNodeList = new ArrayList();
+
+ ExpressionNode expressionNodeLeft = new InstVar(new This("testClass"), "objectVar");
+
+ LiteralNode expressionNodeRight = new LiteralNode();
+ expressionNodeRight.setType(new BaseTypeNode(EnumTypeNode.INT));
+
+ StatementNode statementNode1 = new AssignmentStatementNode(expressionNodeLeft, expressionNodeRight);
+ 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;
+
+ return programNode;
+
+ }
+
+ public static ProgramNode mockFieldNodeAlreadyDeclaredProgrammNode(){
+ ProgramNode programNode = new ProgramNode();
+ List classList = new ArrayList();
+ 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;
+ }
+}
diff --git a/src/test/java/semantic/SemanticTest.java b/src/test/java/semantic/SemanticTest.java
index 83287ca..71604ee 100644
--- a/src/test/java/semantic/SemanticTest.java
+++ b/src/test/java/semantic/SemanticTest.java
@@ -2,29 +2,19 @@ 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;
-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 {
@@ -34,24 +24,18 @@ public class SemanticTest {
}
@Test
- public void alreadyDeclaredLocalFieldVar(){
+ public void alreadyDeclaredLocalFieldVar() {
- ProgramNode programNode = new ProgramNode();
- List classList = new ArrayList();
- 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);
@@ -59,49 +43,121 @@ public class SemanticTest {
}
@Test
- public void shouldWorkWithNoError(){
+ public void alreadyDecleared() {
- ProgramNode programNode = new ProgramNode();
- List classList = new ArrayList();
- 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.mockFieldNodeAlreadyDeclaredProgrammNode();
- MemberNode memberNode2 = new FieldNode(accessTypeNode, new BaseTypeNode(EnumTypeNode.INT), "testVar2");
- classNode.members.add(memberNode2);
-
- 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();
-
- 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(1, SemanticAnalyzer.errors.size());
+ assertInstanceOf(AlreadyDeclearedException.class, SemanticAnalyzer.errors.getFirst());
+ assertNull(typedAst);
+
+ }
+
+ @Test
+ public void shouldWorkWithNoError() {
+
+ //Arrange
+
+ ProgramNode programNode = Mocker.mockCorrectProgrammNode();
+
+ //Act
+
+ ASTNode typedAst = SemanticAnalyzer.generateTast(programNode);
+
+ //Assert
+
assertEquals(0, SemanticAnalyzer.errors.size());
assertEquals(programNode, typedAst);
}
+ @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