Added Exception to TypedAst

This commit is contained in:
ahmad 2024-05-15 21:55:26 +02:00
parent 795001f62b
commit 11a4be8216
15 changed files with 97 additions and 33 deletions

View File

@ -98,9 +98,7 @@ public class Compiler {
} }
public static void main(String[] args) { public static void main(String[] args) {
generateByteCodeFileFromFile(List.of("src/main/resources/JavaTestfiles/ClassWithConstructor.java", generateByteCodeFileFromFile(List.of("src/main/resources/JavaTestfiles/ClassCanBeTyped.java"),
"src/main/resources/JavaTestfiles/ClassWithConstructorAndMethodCall.java", List.of("ClassWithConstructor"));
"src/main/resources/JavaTestfiles/ComplexClass.java"),
List.of("ClassWithConstructor","ClassWithConstructorAndMethodCall","ComplexClass"));
} }
} }

View File

@ -1,6 +1,8 @@
package de.maishai.typedast.typedclass; package de.maishai.typedast.typedclass;
import de.maishai.ast.records.Assignment; import de.maishai.ast.records.Assignment;
import de.maishai.typedast.Exception.TypeMismatchException;
import de.maishai.typedast.Exception.VariableNotDeclaredException;
import de.maishai.typedast.MethodContext; import de.maishai.typedast.MethodContext;
import de.maishai.typedast.TypedExpression; import de.maishai.typedast.TypedExpression;
import de.maishai.typedast.TypedStatement; import de.maishai.typedast.TypedStatement;
@ -33,11 +35,15 @@ public class TypedAssignment implements TypedStatement {
Type typeLeft = getTypeLeft(typedProgram); Type typeLeft = getTypeLeft(typedProgram);
Type typeRight = value.typeCheck(typedProgram); Type typeRight = value.typeCheck(typedProgram);
if (typeLeft.equals(typeRight)) { if (typeLeft.equals(typeRight)) {
type = typeLeft; type = typeLeft;
return typeLeft; return typeLeft;
} }
throw new RuntimeException("type of left not equals with type of right");
TypedProgram.addException(new TypeMismatchException(typeLeft, typeRight));
return Type.VOID;
} }
private Type getTypeLeft(TypedProgram typedProgram) { private Type getTypeLeft(TypedProgram typedProgram) {
@ -56,7 +62,8 @@ public class TypedAssignment implements TypedStatement {
return getTypeFromConstructorOrField(currentClass.getCurrentConstructor(), name, currentClass); return getTypeFromConstructorOrField(currentClass.getCurrentConstructor(), name, currentClass);
} }
throw new RuntimeException("Variable " + name + " not declared"); TypedProgram.addException(new VariableNotDeclaredException(name, currentClass.getClassName()));
return Type.VOID;
} }
private Type getTypeFromMethodOrField(TypedMethod currentMethod, String name, TypedClass currentClass) { private Type getTypeFromMethodOrField(TypedMethod currentMethod, String name, TypedClass currentClass) {
@ -65,7 +72,8 @@ public class TypedAssignment implements TypedStatement {
} else if (currentClass.isThereField(name)) { } else if (currentClass.isThereField(name)) {
return currentClass.getFieldType(name); return currentClass.getFieldType(name);
} else { } else {
throw new RuntimeException("Variable " + name + " not declared in method"); TypedProgram.addException(new VariableNotDeclaredException(name, currentMethod.getName()));
return Type.VOID;
} }
} }
@ -75,7 +83,8 @@ public class TypedAssignment implements TypedStatement {
} else if (currentClass.isThereField(name)) { } else if (currentClass.isThereField(name)) {
return currentClass.getFieldType(name); return currentClass.getFieldType(name);
} else { } else {
throw new RuntimeException("Variable " + name + " not declared in constructor"); TypedProgram.addException(new VariableNotDeclaredException(name, currentConstructor.getName()));
return Type.VOID;
} }
} }

View File

@ -2,6 +2,7 @@ package de.maishai.typedast.typedclass;
import de.maishai.ast.Operator; import de.maishai.ast.Operator;
import de.maishai.ast.records.Binary; import de.maishai.ast.records.Binary;
import de.maishai.typedast.Exception.TypeMismatchException;
import de.maishai.typedast.MethodContext; import de.maishai.typedast.MethodContext;
import de.maishai.typedast.TypedExpression; import de.maishai.typedast.TypedExpression;
import de.maishai.typedast.Type; import de.maishai.typedast.Type;
@ -45,21 +46,21 @@ public class TypedBinary implements TypedExpression {
type = Type.INT; type = Type.INT;
return Type.INT; return Type.INT;
} else { } else {
throw new RuntimeException("Type mismatch in " + op); TypedProgram.addException(new TypeMismatchException(op.toString()));
} }
} else if (op == Operator.GT || op == Operator.LT || op == Operator.GE || op == Operator.LE) { } else if (op == Operator.GT || op == Operator.LT || op == Operator.GE || op == Operator.LE) {
if (leftType == Type.INT && rightType == Type.INT) { if (leftType == Type.INT && rightType == Type.INT) {
type = Type.BOOL; type = Type.BOOL;
return Type.BOOL; return Type.BOOL;
} else { } else {
throw new RuntimeException("Type mismatch in " + op); TypedProgram.addException(new TypeMismatchException(op.toString()));
} }
} else if (op == Operator.AND || op == Operator.OR) { } else if (op == Operator.AND || op == Operator.OR) {
if (leftType == Type.BOOL && rightType == Type.BOOL) { if (leftType == Type.BOOL && rightType == Type.BOOL) {
type = Type.BOOL; type = Type.BOOL;
return Type.BOOL; return Type.BOOL;
} else { } else {
throw new RuntimeException("Type mismatch in " + op); TypedProgram.addException(new TypeMismatchException(op.toString()));
} }
} }
@ -67,7 +68,8 @@ public class TypedBinary implements TypedExpression {
type = rightType; type = rightType;
return type; return type;
} }
throw new RuntimeException("Void can not be compared with Void"); TypedProgram.addException(new TypeMismatchException());
return Type.VOID;
} }
@Override @Override

View File

@ -3,6 +3,8 @@ package de.maishai.typedast.typedclass;
import de.maishai.ast.records.Constructor; import de.maishai.ast.records.Constructor;
import de.maishai.ast.records.Parameter; import de.maishai.ast.records.Parameter;
import de.maishai.typedast.*; import de.maishai.typedast.*;
import de.maishai.typedast.Exception.ConstructorReturnException;
import de.maishai.typedast.Exception.ParameterAlreadyExistsException;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
@ -63,7 +65,7 @@ public class TypedConstructor implements TypedNode {
public void checkIfParameterExists(String paraName) { public void checkIfParameterExists(String paraName) {
if (typedParameters.stream().anyMatch(parameter -> parameter.getParaName().equals(paraName))) { if (typedParameters.stream().anyMatch(parameter -> parameter.getParaName().equals(paraName))) {
throw new RuntimeException("Parameter " + paraName + " already exists"); TypedProgram.addException(new ParameterAlreadyExistsException(paraName));
} }
} }
@ -76,7 +78,8 @@ public class TypedConstructor implements TypedNode {
public Type typeCheck(TypedProgram typedProgram) { public Type typeCheck(TypedProgram typedProgram) {
type = typedBlock.typeCheck(typedProgram); type = typedBlock.typeCheck(typedProgram);
if (type != Type.VOID) { if (type != Type.VOID) {
throw new RuntimeException("Constructor must not habe a return statement"); TypedProgram.addException(new ConstructorReturnException(typedProgram.getCurrentClass().getCurrentConstructor().name));
return Type.VOID;
} }
return type; return type;

View File

@ -1,6 +1,8 @@
package de.maishai.typedast.typedclass; package de.maishai.typedast.typedclass;
import de.maishai.ast.records.Declaration; import de.maishai.ast.records.Declaration;
import de.maishai.typedast.Exception.FieldAlreadyDeclaredException;
import de.maishai.typedast.Exception.NotFoundException;
import de.maishai.typedast.TypedNode; import de.maishai.typedast.TypedNode;
import de.maishai.typedast.Type; import de.maishai.typedast.Type;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
@ -31,11 +33,13 @@ public final class TypedDeclaration implements TypedNode {
public Type typeCheck(TypedProgram typedProgram) { public Type typeCheck(TypedProgram typedProgram) {
if (type.getReference() != null && !typedProgram.getCurrentClass().getClassName().equals(type.getReference())) { if (type.getReference() != null && !typedProgram.getCurrentClass().getClassName().equals(type.getReference())) {
if (!typedProgram.isTypedClassPresent(type.getReference())) { if (!typedProgram.isTypedClassPresent(type.getReference())) {
throw new RuntimeException("Type " + type.getReference() + " not found"); TypedProgram.addException(new NotFoundException(type.getReference()));
return Type.VOID;
} }
} }
if (typedProgram.getCurrentClass().isThereField(name)) { if (typedProgram.getCurrentClass().isThereField(name)) {
throw new RuntimeException("Field " + name + " already declared"); TypedProgram.addException(new FieldAlreadyDeclaredException(name));
return Type.VOID;
} }
return type; return type;
} }

View File

@ -2,6 +2,7 @@ package de.maishai.typedast.typedclass;
import de.maishai.ast.records.*; import de.maishai.ast.records.*;
import de.maishai.typedast.*; import de.maishai.typedast.*;
import de.maishai.typedast.Exception.ConditionException;
import lombok.Data; import lombok.Data;
import static de.maishai.typedast.Help.TypedExpressionHelp.convertExpression; import static de.maishai.typedast.Help.TypedExpressionHelp.convertExpression;
@ -24,7 +25,8 @@ public class TypedDoWhile implements TypedStatement {
@Override @Override
public Type typeCheck(TypedProgram typedProgram) { public Type typeCheck(TypedProgram typedProgram) {
if (cond.typeCheck(typedProgram) != Type.BOOL) { if (cond.typeCheck(typedProgram) != Type.BOOL) {
throw new RuntimeException("Condition must be boolean"); TypedProgram.addException(new ConditionException());
return Type.VOID;
} }
typedBlock.typeCheck(typedProgram); typedBlock.typeCheck(typedProgram);
this.type = Type.VOID; this.type = Type.VOID;

View File

@ -1,6 +1,8 @@
package de.maishai.typedast.typedclass; package de.maishai.typedast.typedclass;
import de.maishai.ast.records.*; import de.maishai.ast.records.*;
import de.maishai.typedast.Exception.FieldNotDeclaredException;
import de.maishai.typedast.Exception.VariableNotDeclaredException;
import de.maishai.typedast.MethodContext; import de.maishai.typedast.MethodContext;
import de.maishai.typedast.TypedExpression; import de.maishai.typedast.TypedExpression;
import de.maishai.typedast.Type; import de.maishai.typedast.Type;
@ -55,7 +57,8 @@ public class TypedFieldVarAccess implements TypedExpression {
type = typedProgram.getCurrentClass().getFieldType(typedFieldVarAccess.getName()); type = typedProgram.getCurrentClass().getFieldType(typedFieldVarAccess.getName());
return type; return type;
} else { } else {
throw new RuntimeException("Field " + name + " not declared"); TypedProgram.addException(new FieldNotDeclaredException(name));
return null;
} }
} }
@ -65,7 +68,8 @@ public class TypedFieldVarAccess implements TypedExpression {
} else if (typedProgram.getCurrentClass().isCurrentMethodPresent()) { } else if (typedProgram.getCurrentClass().isCurrentMethodPresent()) {
return checkMethodVariableType(typedProgram); return checkMethodVariableType(typedProgram);
} else { } else {
throw new RuntimeException("Variable " + name + " not declared"); TypedProgram.addException(new VariableNotDeclaredException(name));
return null;
} }
} }
@ -99,7 +103,8 @@ public class TypedFieldVarAccess implements TypedExpression {
} else if (recursiveOwnerChain instanceof TypedFieldVarAccess typedFieldVarAccess) { } else if (recursiveOwnerChain instanceof TypedFieldVarAccess typedFieldVarAccess) {
type = typedProgram.getCurrentClass().getFieldType(typedFieldVarAccess.getName()); type = typedProgram.getCurrentClass().getFieldType(typedFieldVarAccess.getName());
} else { } else {
throw new RuntimeException("Variable " + name + " not declared"); TypedProgram.addException(new VariableNotDeclaredException(name));
return Type.VOID;
} }
return type; return type;
} }

View File

@ -2,6 +2,7 @@ package de.maishai.typedast.typedclass;
import de.maishai.ast.records.*; import de.maishai.ast.records.*;
import de.maishai.typedast.*; import de.maishai.typedast.*;
import de.maishai.typedast.Exception.ConditionException;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
@ -33,7 +34,8 @@ public class TypedFor implements TypedStatement {
public Type typeCheck(TypedProgram typedProgram) { public Type typeCheck(TypedProgram typedProgram) {
assign.typeCheck(typedProgram); assign.typeCheck(typedProgram);
if (!cond.typeCheck(typedProgram).equals(Type.BOOL)) { if (!cond.typeCheck(typedProgram).equals(Type.BOOL)) {
throw new RuntimeException("Condition must be a boolean"); TypedProgram.addException(new ConditionException());
return Type.VOID;
} }
inc.typeCheck(typedProgram); inc.typeCheck(typedProgram);
type = typedBlock.typeCheck(typedProgram); type = typedBlock.typeCheck(typedProgram);

View File

@ -1,6 +1,9 @@
package de.maishai.typedast.typedclass; package de.maishai.typedast.typedclass;
import de.maishai.ast.records.Declaration; import de.maishai.ast.records.Declaration;
import de.maishai.typedast.Exception.FieldAlreadyDeclaredException;
import de.maishai.typedast.Exception.NotFoundException;
import de.maishai.typedast.Exception.VariableAlreadyDeclaredException;
import de.maishai.typedast.MethodContext; import de.maishai.typedast.MethodContext;
import de.maishai.typedast.TypedNode; import de.maishai.typedast.TypedNode;
import de.maishai.typedast.Type; import de.maishai.typedast.Type;
@ -30,19 +33,22 @@ public final class TypedLocalVariable implements TypedNode {
public Type typeCheck(TypedProgram typedProgram) { public Type typeCheck(TypedProgram typedProgram) {
if (typedProgram.getCurrentClass().isCurrentMethodPresent() && !typedProgram.getCurrentClass().isCurrentConstructorPresent()) { if (typedProgram.getCurrentClass().isCurrentMethodPresent() && !typedProgram.getCurrentClass().isCurrentConstructorPresent()) {
if (typedProgram.getCurrentClass().getCurrentMethod().isLocalVariableInMethod(name)) { if (typedProgram.getCurrentClass().getCurrentMethod().isLocalVariableInMethod(name)) {
throw new RuntimeException("Variable " + name + " already declared"); TypedProgram.addException(new VariableAlreadyDeclaredException(name));
return Type.VOID;
} }
typedProgram.getCurrentClass().getCurrentMethod().getLocalVariables().add(this); typedProgram.getCurrentClass().getCurrentMethod().getLocalVariables().add(this);
return type; return type;
} }
if (!typedProgram.getCurrentClass().isCurrentMethodPresent() && typedProgram.getCurrentClass().isCurrentConstructorPresent()) { if (!typedProgram.getCurrentClass().isCurrentMethodPresent() && typedProgram.getCurrentClass().isCurrentConstructorPresent()) {
if (typedProgram.getCurrentClass().getCurrentConstructor().isLocalVariableInConstructor(name)) { if (typedProgram.getCurrentClass().getCurrentConstructor().isLocalVariableInConstructor(name)) {
throw new RuntimeException("Variable " + name + " already declared"); TypedProgram.addException(new VariableAlreadyDeclaredException(name));
return Type.VOID;
} }
typedProgram.getCurrentClass().getCurrentConstructor().getLocalVariables().add(this); typedProgram.getCurrentClass().getCurrentConstructor().getLocalVariables().add(this);
return type; return type;
} }
throw new RuntimeException("not found method or constructor in class"); TypedProgram.addException(new NotFoundException("method or constructor"));
return Type.VOID;
} }
public void codeGen(MethodVisitor mv, MethodContext ctx) { public void codeGen(MethodVisitor mv, MethodContext ctx) {

View File

@ -97,6 +97,7 @@ public class TypedMethod implements TypedNode {
if (typedBlock.typeCheck(typedProgram).getKind() != returnType.getKind()) { if (typedBlock.typeCheck(typedProgram).getKind() != returnType.getKind()) {
if (hasEvenReturnsInIfElseBlocks()) { if (hasEvenReturnsInIfElseBlocks()) {
throw new RuntimeException("Method " + name + " must have even returns in if else blocks"); throw new RuntimeException("Method " + name + " must have even returns in if else blocks");
} else { } else {
throw new RuntimeException("Method " + name + " must return " + returnType.getKind()); throw new RuntimeException("Method " + name + " must return " + returnType.getKind());
} }

View File

@ -3,6 +3,7 @@ package de.maishai.typedast.typedclass;
import de.maishai.ast.records.Expression; import de.maishai.ast.records.Expression;
import de.maishai.ast.records.New; import de.maishai.ast.records.New;
import de.maishai.typedast.*; import de.maishai.typedast.*;
import de.maishai.typedast.Exception.NotMatchConstructorException;
import lombok.Data; import lombok.Data;
import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes; import org.objectweb.asm.Opcodes;
@ -49,7 +50,8 @@ public class TypedNew implements TypedExpression, TypedStatement {
} }
} }
} }
throw new RuntimeException("No matching constructor found"); TypedProgram.addException(new NotMatchConstructorException());
return Type.VOID;
} }

View File

@ -1,6 +1,7 @@
package de.maishai.typedast.typedclass; package de.maishai.typedast.typedclass;
import de.maishai.ast.records.Parameter; import de.maishai.ast.records.Parameter;
import de.maishai.typedast.Exception.ParameterAlreadyExistsException;
import de.maishai.typedast.Type; import de.maishai.typedast.Type;
import de.maishai.typedast.TypedNode; import de.maishai.typedast.TypedNode;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
@ -36,11 +37,13 @@ public class TypedParameter implements TypedNode {
if (typedProgram.getCurrentClass().isCurrentMethodPresent()) { if (typedProgram.getCurrentClass().isCurrentMethodPresent()) {
if (typedProgram.getCurrentClass().isParameterWitNameInMethod(paraName)) { if (typedProgram.getCurrentClass().isParameterWitNameInMethod(paraName)) {
throw new RuntimeException("Parameter " + paraName + " already exists"); TypedProgram.addException(new ParameterAlreadyExistsException(paraName));
return Type.VOID;
} }
} else if (typedProgram.getCurrentClass().isCurrentConstructorPresent()) { } else if (typedProgram.getCurrentClass().isCurrentConstructorPresent()) {
if (typedProgram.getCurrentClass().isParameterWitNameInConstructor(paraName)) { if (typedProgram.getCurrentClass().isParameterWitNameInConstructor(paraName)) {
throw new RuntimeException("Parameter " + paraName + " already exists"); TypedProgram.addException(new ParameterAlreadyExistsException(paraName));
return Type.VOID;
} }
} }

View File

@ -10,6 +10,8 @@ import java.util.List;
@Getter @Getter
@AllArgsConstructor @AllArgsConstructor
public class TypedProgram { public class TypedProgram {
//list of exceptions
public static List<RuntimeException> exceptions = new ArrayList<>();
private List<TypedClass> typedClasses = new ArrayList<>(); private List<TypedClass> typedClasses = new ArrayList<>();
private TypedClass currentClass; private TypedClass currentClass;
@ -41,6 +43,8 @@ public class TypedProgram {
exitCurrentClass(); exitCurrentClass();
i++; i++;
} }
printExceptions();
} }
public TypedClass getTypedClass(String className) { public TypedClass getTypedClass(String className) {
@ -58,5 +62,22 @@ public class TypedProgram {
public void exitCurrentClass() { public void exitCurrentClass() {
currentClass = null; currentClass = null;
} }
public static void addException(RuntimeException exception) {
if (!exceptions.contains(exception)) {
exceptions.add(exception);
}
}
public void printExceptions() {
if (exceptions.isEmpty()) {
System.out.println("Die Kompilierung wurde fehlerfrei abgeschlossen.");
} else {
System.out.println("Es wurden folgende Fehler während der Kompilierung festgestellt:");
for (int i = 0; i < exceptions.size(); i++) {
System.out.println((i + 1) + ": " + exceptions.get(i).getMessage());
}
}
}
} }

View File

@ -2,6 +2,7 @@ package de.maishai.typedast.typedclass;
import de.maishai.ast.UnaryOperator; import de.maishai.ast.UnaryOperator;
import de.maishai.ast.records.Unary; import de.maishai.ast.records.Unary;
import de.maishai.typedast.Exception.InvalidNotOperationException;
import de.maishai.typedast.MethodContext; import de.maishai.typedast.MethodContext;
import de.maishai.typedast.TypedExpression; import de.maishai.typedast.TypedExpression;
import de.maishai.typedast.Type; import de.maishai.typedast.Type;
@ -30,18 +31,21 @@ public class TypedUnary implements TypedExpression {
if (op == UnaryOperator.NOT) { if (op == UnaryOperator.NOT) {
if (right.typeCheck(typedProgram) != Type.BOOL) { if (right.typeCheck(typedProgram) != Type.BOOL) {
throw new RuntimeException("Not operator must be applied to boolean"); TypedProgram.addException(new InvalidNotOperationException(UnaryOperator.NOT.name(), Type.BOOL.getKind().name()));
return Type.VOID;
} }
return Type.BOOL; return Type.BOOL;
} }
if (op == UnaryOperator.SUB) { if (op == UnaryOperator.SUB) {
if (right.typeCheck(typedProgram) != Type.INT) { if (right.typeCheck(typedProgram) != Type.INT) {
throw new RuntimeException("Minus operator must be applied to int"); TypedProgram.addException(new InvalidNotOperationException(UnaryOperator.SUB.name(), Type.INT.getKind().name()));
return Type.VOID;
} }
return Type.INT; return Type.INT;
} }
throw new RuntimeException("Unknown unary operator"); TypedProgram.addException(new InvalidNotOperationException());
return Type.VOID;
} }
@Override @Override

View File

@ -2,6 +2,7 @@ package de.maishai.typedast.typedclass;
import de.maishai.ast.records.*; import de.maishai.ast.records.*;
import de.maishai.typedast.*; import de.maishai.typedast.*;
import de.maishai.typedast.Exception.ConditionException;
import lombok.Data; import lombok.Data;
import static de.maishai.typedast.Help.TypedExpressionHelp.convertExpression; import static de.maishai.typedast.Help.TypedExpressionHelp.convertExpression;
@ -24,7 +25,8 @@ public class TypedWhile implements TypedStatement {
@Override @Override
public Type typeCheck(TypedProgram typedProgram) { public Type typeCheck(TypedProgram typedProgram) {
if (cond.typeCheck(typedProgram) != Type.BOOL) { if (cond.typeCheck(typedProgram) != Type.BOOL) {
throw new RuntimeException("While condition must be a boolean"); TypedProgram.addException(new ConditionException());
return Type.VOID;
} }
type = typedBlock.typeCheck(typedProgram); type = typedBlock.typeCheck(typedProgram);
return type; return type;