diff --git a/src/main/java/ast/expression/IExpressionNode.java b/src/main/java/ast/expression/IExpressionNode.java index c4c72f5..28b45e3 100644 --- a/src/main/java/ast/expression/IExpressionNode.java +++ b/src/main/java/ast/expression/IExpressionNode.java @@ -1,11 +1,11 @@ package ast.expression; import ast.ASTNode; -import ast.type.type.TypeNode; +import ast.type.type.ITypeNode; import visitor.Visitable; public interface IExpressionNode extends ASTNode, Visitable { - TypeNode getType(); + ITypeNode getType(); } diff --git a/src/main/java/ast/expression/binaryexpression/BinaryExpressionNode.java b/src/main/java/ast/expression/binaryexpression/BinaryExpressionNode.java index d4db5ab..655a3f5 100644 --- a/src/main/java/ast/expression/binaryexpression/BinaryExpressionNode.java +++ b/src/main/java/ast/expression/binaryexpression/BinaryExpressionNode.java @@ -1,7 +1,7 @@ package ast.expression.binaryexpression; import ast.expression.IExpressionNode; -import ast.type.type.TypeNode; +import ast.type.type.*; import semantic.SemanticVisitor; import typechecker.TypeCheckResult; @@ -13,7 +13,7 @@ public class BinaryExpressionNode implements IExpressionNode { } @Override - public TypeNode getType() { + public ITypeNode getType() { return null; } } diff --git a/src/main/java/ast/expression/binaryexpression/CalculationExpressionNode.java b/src/main/java/ast/expression/binaryexpression/CalculationExpressionNode.java index 53adaa2..70451d8 100644 --- a/src/main/java/ast/expression/binaryexpression/CalculationExpressionNode.java +++ b/src/main/java/ast/expression/binaryexpression/CalculationExpressionNode.java @@ -1,6 +1,6 @@ package ast.expression.binaryexpression; -import ast.type.type.TypeNode; +import ast.type.type.*; import semantic.SemanticVisitor; import typechecker.TypeCheckResult; @@ -25,7 +25,7 @@ public class CalculationExpressionNode extends BinaryExpressionNode { } @Override - public TypeNode getType() { + public ITypeNode getType() { return null; } diff --git a/src/main/java/ast/expression/binaryexpression/DotExpressionNode.java b/src/main/java/ast/expression/binaryexpression/DotExpressionNode.java index 9ea8170..cc5f2c6 100644 --- a/src/main/java/ast/expression/binaryexpression/DotExpressionNode.java +++ b/src/main/java/ast/expression/binaryexpression/DotExpressionNode.java @@ -1,6 +1,6 @@ package ast.expression.binaryexpression; -import ast.type.type.TypeNode; +import ast.type.type.*; import semantic.SemanticVisitor; import typechecker.TypeCheckResult; @@ -25,7 +25,7 @@ public class DotExpressionNode extends BinaryExpressionNode { } @Override - public TypeNode getType() { + public ITypeNode getType() { return null; } diff --git a/src/main/java/ast/expression/binaryexpression/DotSubstractionExpressionNode.java b/src/main/java/ast/expression/binaryexpression/DotSubstractionExpressionNode.java index 17c9604..1b43a9f 100644 --- a/src/main/java/ast/expression/binaryexpression/DotSubstractionExpressionNode.java +++ b/src/main/java/ast/expression/binaryexpression/DotSubstractionExpressionNode.java @@ -2,7 +2,7 @@ package ast.expression.binaryexpression; import ast.expression.unaryexpression.MemberAccessNode; import ast.statement.statementexpression.methodcallstatementnexpression.MethodCallStatementExpressionNode; -import ast.type.type.TypeNode; +import ast.type.type.*; import ast.type.ValueNode; import semantic.SemanticVisitor; import typechecker.TypeCheckResult; @@ -37,7 +37,7 @@ public class DotSubstractionExpressionNode extends BinaryExpressionNode { } @Override - public TypeNode getType() { + public ITypeNode getType() { return null; } diff --git a/src/main/java/ast/expression/binaryexpression/NonCalculationExpressionNode.java b/src/main/java/ast/expression/binaryexpression/NonCalculationExpressionNode.java index 8051bd2..5cdebc2 100644 --- a/src/main/java/ast/expression/binaryexpression/NonCalculationExpressionNode.java +++ b/src/main/java/ast/expression/binaryexpression/NonCalculationExpressionNode.java @@ -2,7 +2,7 @@ package ast.expression.binaryexpression; import ast.expression.IExpressionNode; import ast.expression.unaryexpression.UnaryExpressionNode; -import ast.type.type.TypeNode; +import ast.type.type.*; import semantic.SemanticVisitor; import typechecker.TypeCheckResult; @@ -23,7 +23,7 @@ public class NonCalculationExpressionNode extends BinaryExpressionNode { } @Override - public TypeNode getType() { + public ITypeNode getType() { return null; } diff --git a/src/main/java/ast/expression/unaryexpression/UnaryExpressionNode.java b/src/main/java/ast/expression/unaryexpression/UnaryExpressionNode.java index 74be5ff..4393e84 100644 --- a/src/main/java/ast/expression/unaryexpression/UnaryExpressionNode.java +++ b/src/main/java/ast/expression/unaryexpression/UnaryExpressionNode.java @@ -2,7 +2,7 @@ package ast.expression.unaryexpression; import ast.expression.IExpressionNode; import ast.statement.IStatementNode; -import ast.type.type.TypeNode; +import ast.type.type.*; import ast.type.ValueNode; import semantic.SemanticVisitor; import typechecker.TypeCheckResult; @@ -17,7 +17,7 @@ public class UnaryExpressionNode implements IExpressionNode { public NotExpressionNode notExpression; public IStatementNode statement; public IExpressionNode expression; - private TypeNode type; + private ITypeNode type; public UnaryExpressionNode(String value) { if(Objects.equals(value, "this")) { @@ -53,11 +53,11 @@ public class UnaryExpressionNode implements IExpressionNode { } @Override - public TypeNode getType() { + public ITypeNode getType() { return type; } - public void setType(TypeNode type) { + public void setType(ITypeNode type) { this.type = type; } diff --git a/src/main/java/ast/member/ConstructorNode.java b/src/main/java/ast/member/ConstructorNode.java index 0f7a200..52d7604 100644 --- a/src/main/java/ast/member/ConstructorNode.java +++ b/src/main/java/ast/member/ConstructorNode.java @@ -3,11 +3,14 @@ package ast.member; import ast.block.BlockNode; import ast.parameter.ParameterNode; import ast.type.AccessModifierNode; +import semantic.SemanticVisitor; +import typechecker.TypeCheckResult; +import visitor.Visitable; import java.util.ArrayList; import java.util.List; -public class ConstructorNode extends MethodNode { +public class ConstructorNode extends MethodNode { public AccessModifierNode accessType; public String identifier; public List parameters = new ArrayList<>(); diff --git a/src/main/java/ast/member/FieldNode.java b/src/main/java/ast/member/FieldNode.java index 4377f09..f269c40 100644 --- a/src/main/java/ast/member/FieldNode.java +++ b/src/main/java/ast/member/FieldNode.java @@ -1,17 +1,17 @@ package ast.member; import ast.type.AccessModifierNode; -import ast.type.type.TypeNode; +import ast.type.type.ITypeNode; import semantic.SemanticVisitor; import typechecker.TypeCheckResult; import visitor.Visitable; public class FieldNode implements MemberNode, Visitable { public AccessModifierNode accessTypeNode; - public TypeNode type; + public ITypeNode type; public String identifier; - public FieldNode(AccessModifierNode accessTypeNode, TypeNode type, String name){ + public FieldNode(AccessModifierNode accessTypeNode, ITypeNode type, String name){ this.accessTypeNode = accessTypeNode; this.type = type; this.identifier = name; diff --git a/src/main/java/ast/member/MethodNode.java b/src/main/java/ast/member/MethodNode.java index e318068..ecfd598 100644 --- a/src/main/java/ast/member/MethodNode.java +++ b/src/main/java/ast/member/MethodNode.java @@ -3,7 +3,7 @@ package ast.member; import ast.block.BlockNode; import ast.parameter.ParameterNode; import ast.type.AccessModifierNode; -import ast.type.type.TypeNode; +import ast.type.type.*; import bytecode.visitor.MethodVisitor; import semantic.SemanticVisitor; import typechecker.TypeCheckResult; @@ -15,7 +15,7 @@ import java.util.Objects; public class MethodNode implements MemberNode, Visitable { public AccessModifierNode accesModifier; - public TypeNode type; + private ITypeNode type; public Boolean voidType; private String identifier; public List parameters = new ArrayList<>(); @@ -27,9 +27,9 @@ public class MethodNode implements MemberNode, Visitable { this.block = block; } - public MethodNode(String accessModifier, String type, Boolean voidType, String identifier, BlockNode block){ + public MethodNode(String accessModifier, ITypeNode type, Boolean voidType, String identifier, BlockNode block){ this.accesModifier = new AccessModifierNode(accessModifier); - this.type = new TypeNode(type); + this.type = type; this.voidType = voidType; this.identifier = identifier; this.block = block; @@ -71,6 +71,14 @@ public class MethodNode implements MemberNode, Visitable { return identifier; } + public ITypeNode getType() { + return type; + } + + public void setType(ITypeNode type) { + this.type = type; + } + public void setIdentifier(String identifier) { this.identifier = identifier; } diff --git a/src/main/java/ast/parameter/ParameterNode.java b/src/main/java/ast/parameter/ParameterNode.java index 4c81620..257eb68 100644 --- a/src/main/java/ast/parameter/ParameterNode.java +++ b/src/main/java/ast/parameter/ParameterNode.java @@ -1,16 +1,16 @@ package ast.parameter; import ast.ASTNode; -import ast.type.type.TypeNode; +import ast.type.type.*; import semantic.SemanticVisitor; import typechecker.TypeCheckResult; import visitor.Visitable; public class ParameterNode implements ASTNode, Visitable { - public TypeNode type; + public ITypeNode type; public String identifier; - public ParameterNode(TypeNode type, String identifier) { + public ParameterNode(ITypeNode type, String identifier) { this.type = type; this.identifier = identifier; } diff --git a/src/main/java/ast/statement/LocalVariableDeclarationNode.java b/src/main/java/ast/statement/LocalVariableDeclarationNode.java index 3493c3b..3ab54e0 100644 --- a/src/main/java/ast/statement/LocalVariableDeclarationNode.java +++ b/src/main/java/ast/statement/LocalVariableDeclarationNode.java @@ -1,17 +1,17 @@ package ast.statement; import ast.expression.IExpressionNode; -import ast.type.type.TypeNode; +import ast.type.type.*; import semantic.SemanticVisitor; import typechecker.TypeCheckResult; public class LocalVariableDeclarationNode implements IStatementNode { - public TypeNode type; + public ITypeNode type; public String identifier; public String assign; public IExpressionNode expression; - public LocalVariableDeclarationNode(TypeNode type, String identifier, String assign, IExpressionNode expression) { + public LocalVariableDeclarationNode(ITypeNode type, String identifier, String assign, IExpressionNode expression) { this.type = type; this.identifier = identifier; this.assign = assign; diff --git a/src/main/java/ast/statement/statementexpression/AssignStatementExpressionNode.java b/src/main/java/ast/statement/statementexpression/AssignStatementExpressionNode.java index 19b34e5..df8fe79 100644 --- a/src/main/java/ast/statement/statementexpression/AssignStatementExpressionNode.java +++ b/src/main/java/ast/statement/statementexpression/AssignStatementExpressionNode.java @@ -1,8 +1,6 @@ package ast.statement.statementexpression; -import ast.ASTNode; import ast.expression.IExpressionNode; -import ast.type.type.TypeNode; import semantic.SemanticVisitor; import typechecker.TypeCheckResult; diff --git a/src/main/java/ast/statement/statementexpression/AssignableExpressionNode.java b/src/main/java/ast/statement/statementexpression/AssignableExpressionNode.java index 9ccdfec..0fb9fa9 100644 --- a/src/main/java/ast/statement/statementexpression/AssignableExpressionNode.java +++ b/src/main/java/ast/statement/statementexpression/AssignableExpressionNode.java @@ -1,8 +1,6 @@ package ast.statement.statementexpression; -import ast.ASTNode; import ast.expression.unaryexpression.MemberAccessNode; -import ast.type.type.TypeNode; import semantic.SemanticVisitor; import typechecker.TypeCheckResult; diff --git a/src/main/java/ast/type/type/BaseType.java b/src/main/java/ast/type/type/BaseType.java index d88fd99..fdfb293 100644 --- a/src/main/java/ast/type/type/BaseType.java +++ b/src/main/java/ast/type/type/BaseType.java @@ -1,4 +1,30 @@ package ast.type.type; -public class BaseType { +public class BaseType implements ITypeNode { + + private TypeEnum typeEnum; + + public BaseType(TypeEnum typeEnum) { + this.typeEnum = typeEnum; + } + + public TypeEnum getTypeEnum() { + return typeEnum; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + BaseType other = (BaseType) obj; + if (typeEnum != other.typeEnum) + return false; + return true; + } + + } diff --git a/src/main/java/ast/type/type/ITypeNode.java b/src/main/java/ast/type/type/ITypeNode.java new file mode 100644 index 0000000..e449e3c --- /dev/null +++ b/src/main/java/ast/type/type/ITypeNode.java @@ -0,0 +1,5 @@ +package ast.type.type; + +public interface ITypeNode { + +} diff --git a/src/main/java/ast/type/type/ReferenceType.java b/src/main/java/ast/type/type/ReferenceType.java index 4078c3f..2292046 100644 --- a/src/main/java/ast/type/type/ReferenceType.java +++ b/src/main/java/ast/type/type/ReferenceType.java @@ -1,4 +1,33 @@ package ast.type.type; -public class ReferenceType { +public class ReferenceType implements ITypeNode{ + + private String identifier; + + public ReferenceType(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; + ReferenceType other = (ReferenceType) 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/type/TypeEnum.java b/src/main/java/ast/type/type/TypeEnum.java new file mode 100644 index 0000000..d46fac3 --- /dev/null +++ b/src/main/java/ast/type/type/TypeEnum.java @@ -0,0 +1,9 @@ +package ast.type.type; + +public enum TypeEnum { + VOID, + INT, + CHAR, + BOOL; + +} diff --git a/src/main/java/ast/type/type/TypeNode.java b/src/main/java/ast/type/type/TypeNode.java deleted file mode 100644 index 55bf1b2..0000000 --- a/src/main/java/ast/type/type/TypeNode.java +++ /dev/null @@ -1,33 +0,0 @@ -package ast.type.type; - -import ast.type.EnumTypeNode; - -public class TypeNode { - public EnumTypeNode type; - - public TypeNode(String type) { - setType(type); - } - - private void setType(String type) { - switch(type) { - case "int": - this.type = EnumTypeNode.INT; - break; - case "boolean": - this.type = EnumTypeNode.BOOLEAN; - break; - case "char": - this.type = EnumTypeNode.CHAR; - break; - default: - this.type = EnumTypeNode.IDENTIFIER; - } - } - - - public boolean equals(TypeNode o) { - return !o.type.equals(this.type); - } - -} diff --git a/src/main/java/bytecode/ClassCodeGen.java b/src/main/java/bytecode/ClassCodeGen.java index c666881..c911199 100644 --- a/src/main/java/bytecode/ClassCodeGen.java +++ b/src/main/java/bytecode/ClassCodeGen.java @@ -4,7 +4,7 @@ import ast.ClassNode; import ast.member.FieldNode; import ast.member.MemberNode; import ast.member.MethodNode; -import ast.type.type.TypeNode; +import ast.type.type.BaseType; import bytecode.visitor.ClassVisitor; import java.io.File; import org.objectweb.asm.ClassWriter; @@ -44,7 +44,7 @@ public class ClassCodeGen implements ClassVisitor { @Override public void visit(FieldNode fieldNode) { - if(fieldNode.type instanceof TypeNode baseTypeNode){ + if(fieldNode.type instanceof BaseType baseTypeNode){ // classWriter.visitField(mapper.mapAccessTypeToOpcode(fieldNode.accessTypeNode), fieldNode.identifier, mapper.getTypeChar(baseTypeNode.enumType), null, null ); } classWriter.visitEnd(); diff --git a/src/main/java/parser/astBuilder/ASTBuilder.java b/src/main/java/parser/astBuilder/ASTBuilder.java index 642355b..31a8b82 100644 --- a/src/main/java/parser/astBuilder/ASTBuilder.java +++ b/src/main/java/parser/astBuilder/ASTBuilder.java @@ -29,7 +29,7 @@ import ast.statement.statementexpression.methodcallstatementnexpression.ChainedM import ast.statement.statementexpression.methodcallstatementnexpression.MethodCallStatementExpressionNode; import ast.statement.statementexpression.methodcallstatementnexpression.TargetNode; import ast.type.*; -import ast.type.type.TypeNode; +import ast.type.type.*; import org.antlr.v4.runtime.tree.TerminalNode; import parser.generated.*; @@ -68,7 +68,7 @@ public class ASTBuilder extends SimpleJavaBaseVisitor { return new MethodNode((BlockNode) visit(ctx.block())); } else { if(ctx.type() != null) { - MethodNode methodNode = new MethodNode(ctx.AccessModifier().getText(), ctx.type().getText(), false, ctx.Identifier().getText(), (BlockNode) visit(ctx.block())); + MethodNode methodNode = new MethodNode(ctx.AccessModifier().getText(), createTypeNode(ctx.type().getText()), false, ctx.Identifier().getText(), (BlockNode) visit(ctx.block())); for(SimpleJavaParser.ParameterContext parameter : ctx.parameterList().parameter()) { methodNode.addParameter((ParameterNode) visit(parameter)); } @@ -85,12 +85,12 @@ public class ASTBuilder extends SimpleJavaBaseVisitor { @Override public ASTNode visitFieldDeclaration(SimpleJavaParser.FieldDeclarationContext ctx) { - return new FieldNode(new AccessModifierNode(ctx.AccessModifier().getText()), new TypeNode(ctx.type().getText()), ctx.Identifier().getText()); + return new FieldNode(new AccessModifierNode(ctx.AccessModifier().getText()), createTypeNode(ctx.type().getText()), ctx.Identifier().getText()); } @Override public ASTNode visitParameter(SimpleJavaParser.ParameterContext ctx) { - return new ParameterNode(new TypeNode(ctx.type().getText()), ctx.Identifier().getText()); + return new ParameterNode(createTypeNode(ctx.type().getText()), ctx.Identifier().getText()); } @Override @@ -120,7 +120,7 @@ public class ASTBuilder extends SimpleJavaBaseVisitor { @Override public ASTNode visitLocalVariableDeclaration(SimpleJavaParser.LocalVariableDeclarationContext ctx) { - return new LocalVariableDeclarationNode(new TypeNode(ctx.type().getText()), ctx.Identifier().getText(), ctx.Assign().getText(), (IExpressionNode) visit(ctx.expression())); + return new LocalVariableDeclarationNode(createTypeNode(ctx.type().getText()), ctx.Identifier().getText(), ctx.Assign().getText(), (IExpressionNode) visit(ctx.expression())); } @Override @@ -401,4 +401,15 @@ public class ASTBuilder extends SimpleJavaBaseVisitor { } return null; } + + public ITypeNode createTypeNode(String identifier){ + return switch (identifier) { + case "int" -> new BaseType(TypeEnum.INT); + case "boolean" -> new BaseType(TypeEnum.BOOL); + case "char" -> new BaseType(TypeEnum.CHAR); + case "void" -> new BaseType(TypeEnum.VOID); + default -> new ReferenceType(identifier); + }; + } + } diff --git a/src/main/java/semantic/Scope.java b/src/main/java/semantic/Scope.java index 724aed4..39dd2f8 100644 --- a/src/main/java/semantic/Scope.java +++ b/src/main/java/semantic/Scope.java @@ -1,6 +1,6 @@ package semantic; -import ast.type.type.TypeNode; +import ast.type.type.*; import semantic.exeptions.AlreadyDeclearedException; import java.util.HashMap; @@ -8,21 +8,28 @@ import java.util.Stack; public class Scope { - private Stack> localVars; + private Stack> localVars; public Scope() { - localVars = new Stack>(); + localVars = new Stack>(); } - public void addLocalVar(String name, TypeNode type) { + public void addLocalVar(String name, ITypeNode type) { if (this.contains(name)) { throw new AlreadyDeclearedException("Variable " + name + " already exists in this scope"); } localVars.peek().put(name, type); } + public ITypeNode getLocalVar(String name) { + for (HashMap map : localVars) { + return map.get(name); + } + return null; + } + public boolean contains(String name) { - for (HashMap map : localVars) { + for (HashMap map : localVars) { if (map.containsKey(name)) { return true; } @@ -31,7 +38,7 @@ public class Scope { } public void pushScope() { - localVars.push(new HashMap()); + localVars.push(new HashMap()); } public void popScope() { diff --git a/src/main/java/semantic/SemanticAnalyzer.java b/src/main/java/semantic/SemanticAnalyzer.java index 739f04e..1718d01 100644 --- a/src/main/java/semantic/SemanticAnalyzer.java +++ b/src/main/java/semantic/SemanticAnalyzer.java @@ -23,26 +23,22 @@ import ast.statement.statementexpression.NewDeclarationStatementExpressionNode; import ast.statement.statementexpression.crementExpression.DecrementExpressionNode; import ast.statement.statementexpression.crementExpression.IncrementExpressionNode; import ast.statement.statementexpression.methodcallstatementnexpression.MethodCallStatementExpressionNode; -import ast.type.type.BaseType; -import ast.type.type.ReferenceType; -import ast.type.type.TypeNode; +import ast.type.type.*; import semantic.context.Context; -import semantic.exeptions.AlreadyDeclearedException; -import semantic.exeptions.AlreadyDefinedException; -import semantic.exeptions.NotDeclearedException; -import semantic.exeptions.TypeMismatchException; +import semantic.exeptions.*; import typechecker.TypeCheckResult; public class SemanticAnalyzer implements SemanticVisitor { - private static HashMap currentFields = new HashMap<>(); + private static HashMap currentFields = new HashMap<>(); public static ArrayList errors = new ArrayList<>(); private static Context context; private static Scope currentScope; private static ClassNode currentClass; - private static TypeNode currentNullType; + private static ITypeNode currentNullType; + private ITypeNode currentMethodReturnType; public static ASTNode generateTast(ASTNode node) { SemanticAnalyzer semanticCheck = new SemanticAnalyzer(); @@ -111,59 +107,59 @@ public class SemanticAnalyzer implements SemanticVisitor { @Override public TypeCheckResult analyze(MethodNode methodNode) { - var valid = true; + if (methodNode instanceof ConstructorNode) { + return new TypeCheckResult(true, new BaseType(TypeEnum.VOID)); + } else { - for (var otherMethod : currentClass.getMethods()) { - if (Objects.equals(otherMethod, methodNode)) - break; - if (otherMethod.isSame(methodNode)) { - errors.add(new AlreadyDeclearedException( - "Method " + methodNode.getIdentifier() + " is already defined in class " - + currentClass.identifier)); - valid = false; - } - } + var valid = true; - currentScope.pushScope(); - for (var parameter : methodNode.getParameters()) { - var result = parameter.accept(this); - valid = valid && result.isValid(); - try { - currentScope.addLocalVar(parameter.identifier, parameter.type); - } catch (AlreadyDeclearedException e) { - errors.add(new AlreadyDeclearedException(parameter.identifier)); + for (var otherMethod : currentClass.getMethods()) { + if (Objects.equals(otherMethod, methodNode)) + break; + if (otherMethod.isSame(methodNode)) { + errors.add(new AlreadyDeclearedException( + "Method " + methodNode.getIdentifier() + " is already defined in class " + + currentClass.identifier)); + valid = false; + } } - } - // Check if this method is already declared + currentScope.pushScope(); + for (var parameter : methodNode.getParameters()) { + var result = parameter.accept(this); + valid = valid && result.isValid(); + try { + currentScope.addLocalVar(parameter.identifier, parameter.type); + } catch (AlreadyDeclearedException e) { + errors.add(new AlreadyDeclearedException(parameter.identifier)); + } -// currentMethodReturnType = methodDecl.getType(); -// currentNullType = currentMethodReturnType; // Solange nicht in einem Assign oder Methoden-Aufruf dieser Typ + } + // Check if this method is already declared - TypeNode resultType = new TypeNode("void"); + currentMethodReturnType = methodNode.getType(); + currentNullType = currentMethodReturnType; // Solange nicht in einem Assign oder Methoden-Aufruf dieser Typ + + ITypeNode resultType = new BaseType(TypeEnum.VOID); - if (methodNode.block != null) { // gesetzt ist, ist dieser der Rückgabewert der Methode var result = methodNode.block.accept(this); valid = valid && result.isValid(); currentScope.popScope(); resultType = result.getType(); - /* if (resultType == null) { - resultType = new BaseType(Primitives.VOID); + resultType = new BaseType(TypeEnum.VOID); } - if (!resultType.equals(methodDecl.getType())) { - errors.add(new TypeMismatchException("Method-Declaration " + methodDecl.getIdentifier() + " with type " - + methodDecl.getType() + " has at least one Mismatching return Type:" - + TypeHelper.generateLocationString(methodDecl.line, methodDecl.column, fileName))); + if (!resultType.equals(methodNode.getType())) { + errors.add(new TypeMismatchException("Method-Declaration " + methodNode.getIdentifier() + " with type " + + methodNode.getType() + " has at least one Mismatching return Type:")); valid = false; } - */ - } + return new TypeCheckResult(valid, resultType); - return new TypeCheckResult(valid, resultType); + } } @Override @@ -184,7 +180,9 @@ public class SemanticAnalyzer implements SemanticVisitor { @Override public TypeCheckResult analyze(ReturnStatementNode toCheck) { - return null; + + var result = toCheck.expression.accept(this); + return new TypeCheckResult(true, result.getType()); } @Override @@ -201,11 +199,18 @@ public class SemanticAnalyzer implements SemanticVisitor { @Override public TypeCheckResult analyze(BlockNode blockNode) { - + ITypeNode blockReturnType = null; for (IStatementNode statementNode : blockNode.statements) { - statementNode.accept(this); + var result = statementNode.accept(this); + if(result.getType() != null){ + if(blockReturnType == null){ + blockReturnType = result.getType(); + } else { + errors.add(new MultipleReturnTypes("There are multiple Return types")); + } + } } - return new TypeCheckResult(true, null); + return new TypeCheckResult(true, blockReturnType); } @Override @@ -260,7 +265,7 @@ public class SemanticAnalyzer implements SemanticVisitor { // } valid = valid && lResult.isValid() && rResult.isValid(); currentNullType = null; - return new TypeCheckResult(valid, null); // return type is null to get the return type sufficently + return new TypeCheckResult(valid, new BaseType(TypeEnum.VOID)); // return type is null to get the return type sufficently } @Override @@ -322,7 +327,7 @@ public class SemanticAnalyzer implements SemanticVisitor { @Override public TypeCheckResult analyze(CalculationExpressionNode calcNode) { - if(calcNode.calculationExpression != null){ + if (calcNode.calculationExpression != null) { calcNode.calculationExpression.accept(this); } return null; @@ -352,7 +357,7 @@ public class SemanticAnalyzer implements SemanticVisitor { return new TypeCheckResult(false, null); } - return new TypeCheckResult(valid, unary.getType()); + return new TypeCheckResult(valid, currentScope.getLocalVar(unary.identifier)); } } \ No newline at end of file diff --git a/src/main/java/semantic/context/FieldContext.java b/src/main/java/semantic/context/FieldContext.java index 6c594c9..18e8cf7 100644 --- a/src/main/java/semantic/context/FieldContext.java +++ b/src/main/java/semantic/context/FieldContext.java @@ -2,19 +2,19 @@ package semantic.context; import ast.member.FieldNode; import ast.type.*; -import ast.type.type.TypeNode; +import ast.type.type.*; public class FieldContext { private AccessModifierNode accessModifier; - private TypeNode type; + private ITypeNode type; public FieldContext(FieldNode field) { accessModifier = field.accessTypeNode; type = field.type; } - public TypeNode getType() { + public ITypeNode getType() { return type; } diff --git a/src/main/java/semantic/exeptions/MultipleReturnTypes.java b/src/main/java/semantic/exeptions/MultipleReturnTypes.java new file mode 100644 index 0000000..59f92fa --- /dev/null +++ b/src/main/java/semantic/exeptions/MultipleReturnTypes.java @@ -0,0 +1,9 @@ +package semantic.exeptions; + +public class MultipleReturnTypes extends RuntimeException { + + public MultipleReturnTypes(String message) { + super(message); + } + +} diff --git a/src/main/java/typechecker/TypeCheckResult.java b/src/main/java/typechecker/TypeCheckResult.java index 21c12df..f52818d 100644 --- a/src/main/java/typechecker/TypeCheckResult.java +++ b/src/main/java/typechecker/TypeCheckResult.java @@ -1,14 +1,14 @@ package typechecker; -import ast.type.type.TypeNode; +import ast.type.type.ITypeNode; public class TypeCheckResult { private boolean valid; - private TypeNode type; + private ITypeNode type; - public TypeCheckResult(boolean valid, TypeNode type) { + public TypeCheckResult(boolean valid, ITypeNode type) { this.valid = valid; this.type = type; } @@ -17,7 +17,7 @@ public class TypeCheckResult { return valid; } - public TypeNode getType() { + public ITypeNode getType() { return type; } } \ No newline at end of file diff --git a/src/test/java/semantic/EndToTAST.java b/src/test/java/semantic/EndToTAST.java index 2d14077..3da4043 100644 --- a/src/test/java/semantic/EndToTAST.java +++ b/src/test/java/semantic/EndToTAST.java @@ -12,6 +12,7 @@ import parser.astBuilder.ASTBuilder; import parser.generated.SimpleJavaLexer; import parser.generated.SimpleJavaParser; import semantic.exeptions.AlreadyDeclearedException; +import semantic.exeptions.MultipleReturnTypes; import semantic.exeptions.NotDeclearedException; import semantic.exeptions.TypeMismatchException; @@ -208,7 +209,31 @@ public class EndToTAST { CharStream codeCharStream = null; try { - codeCharStream = CharStreams.fromPath(Paths.get("src/test/resources/semantic/endToTAST/TypeMismatchRefType.java")); + codeCharStream = CharStreams.fromPath(Paths.get("src/test/resources/semantic/endToTAST/CorrectRetType.java")); + } catch (IOException e) { + throw new RuntimeException(e); + } + SimpleJavaLexer lexer = new SimpleJavaLexer(codeCharStream); + CommonTokenStream tokenStream = new CommonTokenStream(lexer); + + SimpleJavaParser parser = new SimpleJavaParser(tokenStream); + ParseTree parseTree = parser.program(); + + ASTBuilder astBuilder = new ASTBuilder(); + ProgramNode abstractSyntaxTree = (ProgramNode) astBuilder.visit(parseTree); + + ASTNode tast = SemanticAnalyzer.generateTast(abstractSyntaxTree); + + assertTrue(SemanticAnalyzer.errors.isEmpty()); + + } + + @Test + public void retTypeMismatch(){ + + CharStream codeCharStream = null; + try { + codeCharStream = CharStreams.fromPath(Paths.get("src/test/resources/semantic/endToTAST/retTypeMismatch.java")); } catch (IOException e) { throw new RuntimeException(e); } @@ -228,4 +253,29 @@ public class EndToTAST { } + @Test + public void multipleRetType(){ + + CharStream codeCharStream = null; + try { + codeCharStream = CharStreams.fromPath(Paths.get("src/test/resources/semantic/endToTAST/MultipleRetTypes.java")); + } catch (IOException e) { + throw new RuntimeException(e); + } + SimpleJavaLexer lexer = new SimpleJavaLexer(codeCharStream); + CommonTokenStream tokenStream = new CommonTokenStream(lexer); + + SimpleJavaParser parser = new SimpleJavaParser(tokenStream); + ParseTree parseTree = parser.program(); + + ASTBuilder astBuilder = new ASTBuilder(); + ProgramNode abstractSyntaxTree = (ProgramNode) astBuilder.visit(parseTree); + + ASTNode tast = SemanticAnalyzer.generateTast(abstractSyntaxTree); + + assertFalse(SemanticAnalyzer.errors.isEmpty()); + assertInstanceOf(MultipleReturnTypes.class, SemanticAnalyzer.errors.getFirst()); + + } + } diff --git a/src/test/java/semantic/Mocker.java b/src/test/java/semantic/Mocker.java index c38a37e..1e404af 100644 --- a/src/test/java/semantic/Mocker.java +++ b/src/test/java/semantic/Mocker.java @@ -6,7 +6,7 @@ import ast.member.FieldNode; import ast.member.MethodNode; import ast.parameter.ParameterNode; import ast.type.AccessModifierNode; -import ast.type.type.TypeNode; +import ast.type.type.*; public class Mocker { @@ -16,11 +16,11 @@ public class Mocker { ClassNode c = new ClassNode(); c.identifier = "testClass"; - FieldNode f1 = new FieldNode(new AccessModifierNode("public"), new TypeNode("int"), "a"); + FieldNode f1 = new FieldNode(new AccessModifierNode("public"), new BaseType(TypeEnum.INT), "a"); c.members.add(f1); - FieldNode f2 = new FieldNode(new AccessModifierNode("public"), new TypeNode("int"), "a"); + FieldNode f2 = new FieldNode(new AccessModifierNode("public"), new BaseType(TypeEnum.INT), "a"); c.members.add(f2); @@ -36,7 +36,7 @@ public class Mocker { MethodNode methodNode = new MethodNode(); //Parameter - ParameterNode parameterNode = new ParameterNode(new TypeNode("int"), "a"); + ParameterNode parameterNode = new ParameterNode(new BaseType(TypeEnum.INT), "a"); methodNode.addParameter(parameterNode); @@ -59,7 +59,7 @@ public class Mocker { MethodNode methodNode = new MethodNode(); methodNode.block = new BlockNode(); - methodNode.type = new TypeNode("int"); + methodNode.setType(new BaseType(TypeEnum.INT)); methodNode.setIdentifier("testMethod"); @@ -67,7 +67,7 @@ public class Mocker { MethodNode methodNode1 = new MethodNode(); methodNode1.block = new BlockNode(); - methodNode1.type = new TypeNode("int"); + methodNode1.setType(new BaseType(TypeEnum.INT)); methodNode1.setIdentifier("testMethod"); diff --git a/src/test/resources/semantic/endToTAST/CorrectRetType.java b/src/test/resources/semantic/endToTAST/CorrectRetType.java new file mode 100644 index 0000000..473e8df --- /dev/null +++ b/src/test/resources/semantic/endToTAST/CorrectRetType.java @@ -0,0 +1,7 @@ +public class Example { + + public static int testMethod(int x){ + return x; + } + +} diff --git a/src/test/resources/semantic/endToTAST/CorrectTest.java b/src/test/resources/semantic/endToTAST/CorrectTest.java index 8e3bf62..ee71670 100644 --- a/src/test/resources/semantic/endToTAST/CorrectTest.java +++ b/src/test/resources/semantic/endToTAST/CorrectTest.java @@ -2,7 +2,9 @@ public class Example { public int a; - public static int testMethod(char x){ + public static int testMethod(int b){ + + a = b; } diff --git a/src/test/resources/semantic/endToTAST/MultipleRetTypes.java b/src/test/resources/semantic/endToTAST/MultipleRetTypes.java new file mode 100644 index 0000000..a5680ed --- /dev/null +++ b/src/test/resources/semantic/endToTAST/MultipleRetTypes.java @@ -0,0 +1,8 @@ +public class Example { + + public static int testMethod(int x, char c){ + return x; + return c; + } + +} diff --git a/src/test/resources/semantic/endToTAST/retTypeMismatch.java b/src/test/resources/semantic/endToTAST/retTypeMismatch.java new file mode 100644 index 0000000..d3a2674 --- /dev/null +++ b/src/test/resources/semantic/endToTAST/retTypeMismatch.java @@ -0,0 +1,7 @@ +public class Example { + + public static int testMethod(char x){ + return x; + } + +}