diff --git a/src/main/java/de/maishai/ExpressionGenerator.java b/src/main/java/de/maishai/ExpressionGenerator.java index 89421d8..ae2a638 100644 --- a/src/main/java/de/maishai/ExpressionGenerator.java +++ b/src/main/java/de/maishai/ExpressionGenerator.java @@ -46,7 +46,8 @@ public class ExpressionGenerator extends DecafBaseVisitor { Expression recipient = null; if (ctx.fieldVarAccess().recipient() != null) { List recipientList = ctx.fieldVarAccess().recipient(); - recipient = ExpressionGenerator.generateRecursiveOwnerChain(recipientList, ctx.fieldVarAccess().newCall() != null ? StatementGenerator.generateNew(ctx.fieldVarAccess().newCall()) : null); + recipient = ExpressionGenerator.generateRecursiveOwnerChain(recipientList, ctx.fieldVarAccess().newCall() != null ? StatementGenerator.generateNew(ctx.fieldVarAccess().newCall()) : null, isField); + return new FieldVarAccess(true, recipient, ctx.fieldVarAccess().id().IDENTIFIER().getText()); } return new FieldVarAccess(isField, recipient, ctx.fieldVarAccess().id().IDENTIFIER().getText()); } @@ -106,7 +107,7 @@ public class ExpressionGenerator extends DecafBaseVisitor { Expression recursiveOwnerChain = null; if (ctx.methCall().recipient() != null) { List recipientList = ctx.methCall().recipient(); - recursiveOwnerChain = ExpressionGenerator.generateRecursiveOwnerChain(recipientList, ctx.methCall().newCall() != null ? StatementGenerator.generateNew(ctx.methCall().newCall()) : null); + recursiveOwnerChain = ExpressionGenerator.generateRecursiveOwnerChain(recipientList, ctx.methCall().newCall() != null ? StatementGenerator.generateNew(ctx.methCall().newCall()) : null, isField); } List args = new ArrayList<>(); if (ctx.methCall().methName().args() != null) { @@ -115,7 +116,10 @@ public class ExpressionGenerator extends DecafBaseVisitor { args.add(astExpr); } } - return new MethodCall(new FieldVarAccess(isField, recursiveOwnerChain, ctx.methCall().methName().id().IDENTIFIER().getText()), args); + if (recursiveOwnerChain == null) { + return new MethodCall(new FieldVarAccess(isField, null, ctx.methCall().methName().id().IDENTIFIER().getText()), args); + } + return new MethodCall(new FieldVarAccess(true, recursiveOwnerChain, ctx.methCall().methName().id().IDENTIFIER().getText()), args); } @Override @@ -124,7 +128,7 @@ public class ExpressionGenerator extends DecafBaseVisitor { } - public static Expression generateRecursiveOwnerChain(List ctxList, Expression recipient) { + public static Expression generateRecursiveOwnerChain(List ctxList, Expression recipient, Boolean isField) { if (ctxList.isEmpty()) { return recipient; } @@ -132,7 +136,10 @@ public class ExpressionGenerator extends DecafBaseVisitor { DecafParser.RecipientContext ctx = ctxList.get(lastElement); ctxList.remove(lastElement); if (ctx.id() != null) { - return new FieldVarAccess(true, generateRecursiveOwnerChain(ctxList, recipient), ctx.id().IDENTIFIER().getText()); + if (ctxList.isEmpty()) { + return new FieldVarAccess(isField, recipient, ctx.id().IDENTIFIER().getText()); + } + return new FieldVarAccess(true, generateRecursiveOwnerChain(ctxList, recipient, isField), ctx.id().IDENTIFIER().getText()); } if (ctx.methName() != null) { List args = new ArrayList<>(); @@ -142,7 +149,10 @@ public class ExpressionGenerator extends DecafBaseVisitor { args.add(astExpr); } } - return new MethodCall(new FieldVarAccess(true, generateRecursiveOwnerChain(ctxList, recipient), ctx.methName().id().IDENTIFIER().getText()), args); + if (ctxList.isEmpty()) { + return new MethodCall(new FieldVarAccess(isField, recipient, ctx.methName().id().IDENTIFIER().getText()), args); + } + return new MethodCall(new FieldVarAccess(true, generateRecursiveOwnerChain(ctxList, recipient, isField), ctx.methName().id().IDENTIFIER().getText()), args); } throw new RuntimeException(); diff --git a/src/main/java/de/maishai/StatementGenerator.java b/src/main/java/de/maishai/StatementGenerator.java index 2e2ac86..206472d 100644 --- a/src/main/java/de/maishai/StatementGenerator.java +++ b/src/main/java/de/maishai/StatementGenerator.java @@ -101,9 +101,13 @@ public class StatementGenerator extends DecafBaseVisitor> { } private FieldVarAccess generateField(DecafParser.FieldVarAccessContext fieldIdContext) { - return new FieldVarAccess(fieldIdContext.THIS() != null, - ExpressionGenerator.generateRecursiveOwnerChain(fieldIdContext.recipient(), - null), fieldIdContext.id().IDENTIFIER().getText()); + Boolean isField = fieldIdContext.THIS() != null; + Expression recipient = null; + if (fieldIdContext.recipient() != null) { + recipient = ExpressionGenerator.generateRecursiveOwnerChain(fieldIdContext.recipient(), null, isField); + return new FieldVarAccess(true, recipient, fieldIdContext.id().IDENTIFIER().getText()); + } + return new FieldVarAccess(isField, recipient, fieldIdContext.id().IDENTIFIER().getText()); } @Override @@ -115,11 +119,6 @@ public class StatementGenerator extends DecafBaseVisitor> { @Override public List visitMethodCall(DecafParser.MethodCallContext ctx) { boolean isField = ctx.methCall().THIS() != null; - Expression recursiveOwnerChain = null; - if (ctx.methCall().recipient() != null) { - List recipientList = ctx.methCall().recipient(); - recursiveOwnerChain = ExpressionGenerator.generateRecursiveOwnerChain(recipientList, ctx.methCall().newCall() != null ? generateNew(ctx.methCall().newCall()) : null); - } List args = new ArrayList<>(); if (ctx.methCall().methName().args() != null) { for (var expr : ctx.methCall().methName().args().expr()) { @@ -127,6 +126,12 @@ public class StatementGenerator extends DecafBaseVisitor> { args.add(astExpr); } } + Expression recursiveOwnerChain = null; + if (ctx.methCall().recipient() != null) { + List recipientList = ctx.methCall().recipient(); + recursiveOwnerChain = ExpressionGenerator.generateRecursiveOwnerChain(recipientList, ctx.methCall().newCall() != null ? generateNew(ctx.methCall().newCall()) : null, isField); + return List.of(new MethodCall(new FieldVarAccess(true, recursiveOwnerChain, ctx.methCall().methName().id().IDENTIFIER().getText()), args)); + } return List.of(new MethodCall(new FieldVarAccess(isField, recursiveOwnerChain, ctx.methCall().methName().id().IDENTIFIER().getText()), args)); } diff --git a/src/main/java/de/maishai/typedast/typedclass/TypedAssignment.java b/src/main/java/de/maishai/typedast/typedclass/TypedAssignment.java index de2d0ed..bb251ef 100644 --- a/src/main/java/de/maishai/typedast/typedclass/TypedAssignment.java +++ b/src/main/java/de/maishai/typedast/typedclass/TypedAssignment.java @@ -31,11 +31,15 @@ public class TypedAssignment implements TypedStatement { public void convertToTypedAssignment(TypedProgram typedProgram, Assignment untyped) { value = convertExpression(typedProgram, untyped.value()); location = new TypedFieldVarAccess(typedProgram, untyped.location()); - //location.typeCheck(typedProgram); } @Override public Type typeCheck(TypedProgram typedProgram) { + TypedClass currentClass = typedProgram.getCurrentClass(); + + if (currentClass.isCurrentMainMethodPresent() && location.getField() && location.getRecursiveOwnerChain() == null) { + throw new RuntimeException("Main Method, is not allowed to have fields, they are not static"); + } Type typeLeft = getTypeLeft(typedProgram); Type typeRight = value.typeCheck(typedProgram); @@ -70,7 +74,7 @@ public class TypedAssignment implements TypedStatement { if (currentMethod.isLocalVariableInMethod(name)) { return currentMethod.getLocalVariableType(name); } else if (currentClass.isThereField(name)) { - throw new RuntimeException("Field Variable "+ name + " should be used with `this´"); + throw new RuntimeException("Field Variable " + name + " should be used with `this´"); } else { throw new RuntimeException("Variable " + name + " not declared in method"); } @@ -80,7 +84,7 @@ public class TypedAssignment implements TypedStatement { if (currentConstructor.isLocalVariableInConstructor(name)) { return currentConstructor.getLocalVariableType(name); } else if (currentClass.isThereField(name)) { - throw new RuntimeException("Field Variable "+ name+ " should be used with `this´"); + throw new RuntimeException("Field Variable " + name + " should be used with `this´"); } else { throw new RuntimeException("Variable " + name + " not declared in constructor"); } @@ -88,7 +92,7 @@ public class TypedAssignment implements TypedStatement { @Override public void codeGen(MethodContext ctx) { - if(value instanceof TypedMethodCall) { + if (value instanceof TypedMethodCall) { value.codeGen(ctx); getOwnerChain(ctx); } else { @@ -112,7 +116,7 @@ public class TypedAssignment implements TypedStatement { return; } MethodContext.LocalVariable localVariable = localVariableOptional.get(); - if(value.getType().getKind() == Type.Kind.REFERENCE) { + if (value.getType().getKind() == Type.Kind.REFERENCE) { LOGGER.finest("ASTORE " + localVariable.index()); ctx.getMv().visitVarInsn(Opcodes.ASTORE, localVariable.index()); } else { diff --git a/src/main/java/de/maishai/typedast/typedclass/TypedBinary.java b/src/main/java/de/maishai/typedast/typedclass/TypedBinary.java index 530c6f6..450e6c1 100644 --- a/src/main/java/de/maishai/typedast/typedclass/TypedBinary.java +++ b/src/main/java/de/maishai/typedast/typedclass/TypedBinary.java @@ -52,8 +52,8 @@ public class TypedBinary implements TypedExpression { } else { throw new RuntimeException("Type mismatch in " + op); } - } else if(op == Operator.EQ || op == Operator.NE || op == Operator.AND || op == Operator.OR){ - if(leftType == Type.INT && rightType == Type.INT || leftType == Type.BOOL && rightType == Type.BOOL){ + } else if (op == Operator.EQ || op == Operator.NE || op == Operator.AND || op == Operator.OR) { + if (leftType == Type.INT && rightType == Type.INT || leftType == Type.BOOL && rightType == Type.BOOL) { type = Type.BOOL; return Type.BOOL; } else { diff --git a/src/main/java/de/maishai/typedast/typedclass/TypedBlock.java b/src/main/java/de/maishai/typedast/typedclass/TypedBlock.java index fc8a692..8bb1b03 100644 --- a/src/main/java/de/maishai/typedast/typedclass/TypedBlock.java +++ b/src/main/java/de/maishai/typedast/typedclass/TypedBlock.java @@ -97,16 +97,20 @@ public class TypedBlock implements TypedNode { return type; } - private void clearLocalVariable(TypedProgram typedProgram){ - for(var typedLocalVariable : vars){ - if (typedProgram.getCurrentClass().isCurrentMethodPresent() && !typedProgram.getCurrentClass().isCurrentConstructorPresent()) { - if (typedProgram.getCurrentClass().getCurrentMethod().isLocalVariableInMethod(typedLocalVariable.getName())) { - typedProgram.getCurrentClass().getCurrentMethod().deleteLocalVariableInMethod(typedLocalVariable.getName()); + private void clearLocalVariable(TypedProgram typedProgram) { + TypedClass typedClass = typedProgram.getCurrentClass(); + TypedMethod typedMethod = typedClass.getCurrentMethod(); + TypedConstructor typedConstructor = typedClass.getCurrentConstructor(); + + for (var typedLocalVariable : vars) { + if (typedClass.isCurrentMethodPresent() && !typedClass.isCurrentConstructorPresent()) { + if (typedMethod.isLocalVariableInMethod(typedLocalVariable.getName())) { + typedMethod.deleteLocalVariableInMethod(typedLocalVariable.getName()); } } - if (!typedProgram.getCurrentClass().isCurrentMethodPresent() && typedProgram.getCurrentClass().isCurrentConstructorPresent()) { - if (typedProgram.getCurrentClass().getCurrentConstructor().isLocalVariableInConstructor(typedLocalVariable.getName())) { - typedProgram.getCurrentClass().getCurrentConstructor().deleteLocalVariableInConstructor(typedLocalVariable.getName()); + if (!typedClass.isCurrentMethodPresent() && typedClass.isCurrentConstructorPresent()) { + if (typedConstructor.isLocalVariableInConstructor(typedLocalVariable.getName())) { + typedConstructor.deleteLocalVariableInConstructor(typedLocalVariable.getName()); } } } diff --git a/src/main/java/de/maishai/typedast/typedclass/TypedBoolLiteral.java b/src/main/java/de/maishai/typedast/typedclass/TypedBoolLiteral.java index c41cd22..7d38bd4 100644 --- a/src/main/java/de/maishai/typedast/typedclass/TypedBoolLiteral.java +++ b/src/main/java/de/maishai/typedast/typedclass/TypedBoolLiteral.java @@ -17,7 +17,6 @@ public class TypedBoolLiteral implements TypedExpression { private Boolean value; private Type type; - public TypedBoolLiteral(BoolLiteral unTypedBoolLiteral) { convertToTypedBoolLiteral(unTypedBoolLiteral); } diff --git a/src/main/java/de/maishai/typedast/typedclass/TypedCharLiteral.java b/src/main/java/de/maishai/typedast/typedclass/TypedCharLiteral.java index ee28483..30b076c 100644 --- a/src/main/java/de/maishai/typedast/typedclass/TypedCharLiteral.java +++ b/src/main/java/de/maishai/typedast/typedclass/TypedCharLiteral.java @@ -13,7 +13,7 @@ public class TypedCharLiteral implements TypedExpression { private char value; private Type type; - public TypedCharLiteral( CharLiteral unTypedCharLiteral) { + public TypedCharLiteral(CharLiteral unTypedCharLiteral) { convertToCharLiteral(unTypedCharLiteral); } diff --git a/src/main/java/de/maishai/typedast/typedclass/TypedClass.java b/src/main/java/de/maishai/typedast/typedclass/TypedClass.java index 9c0ffea..f1bccbb 100644 --- a/src/main/java/de/maishai/typedast/typedclass/TypedClass.java +++ b/src/main/java/de/maishai/typedast/typedclass/TypedClass.java @@ -6,6 +6,7 @@ import de.maishai.ast.records.Declaration; import de.maishai.ast.records.Method; import de.maishai.typedast.ClassContext; import de.maishai.typedast.Type; +import de.maishai.typedast.TypedExpression; import de.maishai.typedast.TypedNode; import lombok.AllArgsConstructor; import lombok.Data; @@ -28,22 +29,24 @@ public class TypedClass implements TypedNode { private TypedMethod currentMethod; private TypedConstructor currentConstructor; private Type type; + private boolean isMainCurrentMethod; public TypedClass(Class c) { className = c.classname(); type = Type.REFERENCE(className); + isMainCurrentMethod = false; } - public boolean isParameterNameInCurrentConstructor(String parameterName) { - if (currentConstructor == null) { - return false; - } - for (TypedParameter p : currentConstructor.getTypedParameters()) { - if (p.getParaName().equals(parameterName)) { - return true; - } - } - return false; + public TypedClass(String className, List typedDeclarations, List typedMethods, List typedConstructors, TypedMain typedMain, TypedMethod currentMethod, TypedConstructor currentConstructor, Type type) { + this.className = className; + this.typedDeclarations = typedDeclarations; + this.typedMethods = typedMethods; + this.typedConstructors = typedConstructors; + this.typedMain = typedMain; + this.currentMethod = currentMethod; + this.currentConstructor = currentConstructor; + this.type = type; + isMainCurrentMethod = false; } public void convertMethodsAndConstructorsAndFields(TypedProgram typedProgram, Class c) { @@ -86,18 +89,40 @@ public class TypedClass implements TypedNode { if (c.mainmeth() != null) { enterCurrentMethod(typedMain.getTypedMethod()); + isMainCurrentMethod = true; typedMain.convertToTypedMethod(typedProgram, c); + isMainCurrentMethod = false; exitCurrentMethod(); } else { typedMain = null; } } + public void checkMethodExists(TypedMethod typedMethod) { + typedMethods.stream().filter(method -> method.equals(typedMethod)).findFirst().ifPresentOrElse( + method -> { + throw new RuntimeException("Method " + typedMethod.getName() + " already exists"); + }, () -> { + }); + } + @Override public Type typeCheck(TypedProgram typedProgram) { return type; } + public boolean isParameterNameInCurrentConstructor(String parameterName) { + if (currentConstructor == null) { + return false; + } + for (TypedParameter p : currentConstructor.getTypedParameters()) { + if (p.getParaName().equals(parameterName)) { + return true; + } + } + return false; + } + public boolean isParameterWitNameInCurrentMethod(String parameterName) { return this.getCurrentMethod().getTypedParameters().stream().anyMatch(parameter -> parameter.getParaName().equals(parameterName)); } @@ -174,6 +199,9 @@ public class TypedClass implements TypedNode { return currentConstructor != null; } + public boolean isCurrentMainMethodPresent() { + return isMainCurrentMethod; + } public byte[] codeGen() { ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS); diff --git a/src/main/java/de/maishai/typedast/typedclass/TypedConstructor.java b/src/main/java/de/maishai/typedast/typedclass/TypedConstructor.java index b4911a7..6546d7c 100644 --- a/src/main/java/de/maishai/typedast/typedclass/TypedConstructor.java +++ b/src/main/java/de/maishai/typedast/typedclass/TypedConstructor.java @@ -33,6 +33,32 @@ public class TypedConstructor implements TypedNode { this.typedBlock = typedBlock; } + + public void convertToTypedConstructor(TypedProgram typedProgram, Constructor unTypedConstructor) { + name = unTypedConstructor.className(); + convertToTypedParameter(typedProgram, unTypedConstructor.params()); + type = Type.VOID; + } + + private void convertToTypedParameter(TypedProgram typedProgram, List params) { + for (Parameter param : params) { + TypedParameter typedParameter = new TypedParameter(typedProgram, param); + checkIfParameterExists(typedParameter.getParaName()); + typedParameters.add(typedParameter); + localVariables.add(new TypedLocalVariable(typedParameter.getParaName(), typedParameter.getType())); + } + } + + @Override + public Type typeCheck(TypedProgram typedProgram) { + type = typedBlock.typeCheck(typedProgram); + if (type != Type.VOID) { + throw new RuntimeException("Constructor must not habe a return statement"); + } + + return type; + } + public TypedConstructor(TypedProgram typedProgram, Constructor unTypedConstructor) { convertToTypedConstructor(typedProgram, unTypedConstructor); } @@ -53,19 +79,7 @@ public class TypedConstructor implements TypedNode { return localVariables.stream().filter(localVariable -> localVariable.getName().equals(localVarName)).findFirst().get().getType(); } - public void convertToTypedConstructor(TypedProgram typedProgram, Constructor unTypedConstructor) { - name = unTypedConstructor.className(); - - for (Parameter param : unTypedConstructor.params()) { - TypedParameter typedParameter = new TypedParameter(typedProgram, param); - checkIfParameterExists(typedParameter.getParaName()); - typedParameters.add(typedParameter); - localVariables.add(new TypedLocalVariable(typedParameter.getParaName(), typedParameter.getType())); - } - type = Type.VOID; - } - - public void checkIfParameterExists(String paraName) { + private void checkIfParameterExists(String paraName) { if (typedParameters.stream().anyMatch(parameter -> parameter.getParaName().equals(paraName))) { throw new RuntimeException("Parameter " + paraName + " already exists"); } @@ -75,20 +89,11 @@ public class TypedConstructor implements TypedNode { this.typedBlock = new TypedBlock(typedProgram, unTypedConstructor.block()); typeCheck(typedProgram); } - public void deleteLocalVariableInConstructor(String localVarName){ + + public void deleteLocalVariableInConstructor(String localVarName) { localVariables.removeIf(localVariable -> localVariable.getName().equals(localVarName)); } - @Override - public Type typeCheck(TypedProgram typedProgram) { - type = typedBlock.typeCheck(typedProgram); - if (type != Type.VOID) { - throw new RuntimeException("Constructor must not habe a return statement"); - } - - return type; - } - public void codeGen(ClassContext ctx) { int accessModifier = Opcodes.ACC_PUBLIC; diff --git a/src/main/java/de/maishai/typedast/typedclass/TypedDeclaration.java b/src/main/java/de/maishai/typedast/typedclass/TypedDeclaration.java index d653b54..33281c1 100644 --- a/src/main/java/de/maishai/typedast/typedclass/TypedDeclaration.java +++ b/src/main/java/de/maishai/typedast/typedclass/TypedDeclaration.java @@ -29,12 +29,15 @@ public final class TypedDeclaration implements TypedNode { @Override public Type typeCheck(TypedProgram typedProgram) { - if (type.getReference() != null && !typedProgram.getCurrentClass().getClassName().equals(type.getReference())) { + TypedClass currentClass = typedProgram.getCurrentClass(); + + if (type.getReference() != null && !currentClass.getClassName().equals(type.getReference())) { if (!typedProgram.isTypedClassPresent(type.getReference())) { throw new RuntimeException("Type " + type.getReference() + " not found"); } } - if (typedProgram.getCurrentClass().isThereField(name)) { + + if (currentClass.isThereField(name)) { throw new RuntimeException("Field " + name + " already declared"); } return type; diff --git a/src/main/java/de/maishai/typedast/typedclass/TypedFieldVarAccess.java b/src/main/java/de/maishai/typedast/typedclass/TypedFieldVarAccess.java index bcc0a07..9b6c7c5 100644 --- a/src/main/java/de/maishai/typedast/typedclass/TypedFieldVarAccess.java +++ b/src/main/java/de/maishai/typedast/typedclass/TypedFieldVarAccess.java @@ -48,22 +48,24 @@ public class TypedFieldVarAccess implements TypedExpression { } private Type checkFieldOrMethodType(TypedProgram typedProgram) { - if (typedProgram.getCurrentClass().isThereField(name)) { + TypedClass currentClass = typedProgram.getCurrentClass(); + + if (currentClass.isThereField(name)) { return checkTypeField(typedProgram); - } else if (typedProgram.getCurrentClass().isMethodOfCurrentClass(name)) { - type = typedProgram.getCurrentClass().getMethodType(name); + } else if (currentClass.isMethodOfCurrentClass(name)) { + type = currentClass.getMethodType(name); return type; } else if (recursiveOwnerChain instanceof TypedFieldVarAccess typedFieldVarAccess) { - - if (typedProgram.isClassWithNamePresent(recursiveOwnerChain.getType().getReference())) { + boolean isClassWithNamePresent = typedProgram.isClassWithNamePresent(recursiveOwnerChain.getType().getReference()); + if (isClassWithNamePresent) { Type typeofFieldNameInClass = typedProgram.getTypeOfFieldNameInClass(recursiveOwnerChain.getType().getReference(), name); - if(typeofFieldNameInClass != null){ + if (typeofFieldNameInClass != null) { return typeofFieldNameInClass; - }else{ + } else { throw new RuntimeException("Field " + name + " not declared in class " + recursiveOwnerChain.getType().getReference()); } } - type = typedProgram.getCurrentClass().getFieldType(typedFieldVarAccess.getName()); + type = currentClass.getFieldType(typedFieldVarAccess.getName()); return type; } else { throw new RuntimeException("Field " + name + " not declared"); @@ -71,9 +73,11 @@ public class TypedFieldVarAccess implements TypedExpression { } private Type checkVariableType(TypedProgram typedProgram) { - if (typedProgram.getCurrentClass().isCurrentConstructorPresent()) { + TypedClass currentClass = typedProgram.getCurrentClass(); + + if (currentClass.isCurrentConstructorPresent()) { return checkConstructorVariableType(typedProgram); - } else if (typedProgram.getCurrentClass().isCurrentMethodPresent()) { + } else if (currentClass.isCurrentMethodPresent()) { return checkMethodVariableType(typedProgram); } else { throw new RuntimeException("Variable " + name + " not declared"); @@ -81,10 +85,13 @@ public class TypedFieldVarAccess implements TypedExpression { } private Type checkConstructorVariableType(TypedProgram typedProgram) { - if (typedProgram.getCurrentClass().isParameterNameInCurrentConstructor(name)) { - type = typedProgram.getCurrentClass().getParameterTypeInCurrentConstructor(name); - } else if (typedProgram.getCurrentClass().getCurrentConstructor().isLocalVariablePresent(name)) { - type = typedProgram.getCurrentClass().getCurrentConstructor().getLocalVariableType(name); + TypedClass currentClass = typedProgram.getCurrentClass(); + TypedConstructor currentConstructor = currentClass.getCurrentConstructor(); + + if (currentClass.isParameterNameInCurrentConstructor(name)) { + type = currentClass.getParameterTypeInCurrentConstructor(name); + } else if (currentConstructor.isLocalVariablePresent(name)) { + type = currentConstructor.getLocalVariableType(name); } else { return checkFieldOrMethodOrRecursiveType(typedProgram); } @@ -92,10 +99,13 @@ public class TypedFieldVarAccess implements TypedExpression { } private Type checkMethodVariableType(TypedProgram typedProgram) { - if (typedProgram.getCurrentClass().isParameterWitNameInCurrentMethod(name)) { - type = typedProgram.getCurrentClass().getParameterTypeInCurrentMethod(name); - } else if (typedProgram.getCurrentClass().getCurrentMethod().isLocalVariablePresent(name)) { - type = typedProgram.getCurrentClass().getCurrentMethod().getLocalVariableType(name); + TypedClass currentClass = typedProgram.getCurrentClass(); + TypedMethod currentMethod = currentClass.getCurrentMethod(); + + if (currentClass.isParameterWitNameInCurrentMethod(name)) { + type = currentClass.getParameterTypeInCurrentMethod(name); + } else if (currentMethod.isLocalVariablePresent(name)) { + type = currentMethod.getLocalVariableType(name); } else { return checkFieldOrMethodOrRecursiveType(typedProgram); } @@ -103,17 +113,20 @@ public class TypedFieldVarAccess implements TypedExpression { } private Type checkFieldOrMethodOrRecursiveType(TypedProgram typedProgram) { - if (typedProgram.getCurrentClass().isThereField(name)) { - type = typedProgram.getCurrentClass().getFieldType(name); - } else if (typedProgram.getCurrentClass().isMethodOfCurrentClass(name)) { - type = typedProgram.getCurrentClass().getMethodType(name); + TypedClass currentClass = typedProgram.getCurrentClass(); + + if (currentClass.isThereField(name)) { + type = currentClass.getFieldType(name); + } else if (currentClass.isMethodOfCurrentClass(name)) { + type = currentClass.getMethodType(name); } else if (recursiveOwnerChain instanceof TypedFieldVarAccess typedFieldVarAccess) { - type = typedProgram.getCurrentClass().getFieldType(typedFieldVarAccess.getName()); + type = currentClass.getFieldType(typedFieldVarAccess.getName()); } else { throw new RuntimeException("Variable " + name + " not declared"); } return type; } + private Type checkTypeField(TypedProgram typedProgram) { if (recursiveOwnerChain != null) { if (recursiveOwnerChain.getType() != null) { @@ -123,6 +136,7 @@ public class TypedFieldVarAccess implements TypedExpression { type = typedProgram.getCurrentClass().getFieldType(name); return type; } + @Override public void codeGen(MethodContext ctx) { if (recursiveOwnerChain != null) { diff --git a/src/main/java/de/maishai/typedast/typedclass/TypedIntLiteral.java b/src/main/java/de/maishai/typedast/typedclass/TypedIntLiteral.java index 0401b62..8f5942b 100644 --- a/src/main/java/de/maishai/typedast/typedclass/TypedIntLiteral.java +++ b/src/main/java/de/maishai/typedast/typedclass/TypedIntLiteral.java @@ -20,7 +20,6 @@ public class TypedIntLiteral implements TypedExpression { private Integer value; private Type type; - public TypedIntLiteral(IntLiteral unTypedIntLiteral) { convertToTypedIntLiteral(unTypedIntLiteral); } diff --git a/src/main/java/de/maishai/typedast/typedclass/TypedLocalVariable.java b/src/main/java/de/maishai/typedast/typedclass/TypedLocalVariable.java index ad73cbf..710cc1c 100644 --- a/src/main/java/de/maishai/typedast/typedclass/TypedLocalVariable.java +++ b/src/main/java/de/maishai/typedast/typedclass/TypedLocalVariable.java @@ -28,18 +28,22 @@ public final class TypedLocalVariable implements TypedNode { @Override public Type typeCheck(TypedProgram typedProgram) { - if (typedProgram.getCurrentClass().isCurrentMethodPresent() && !typedProgram.getCurrentClass().isCurrentConstructorPresent()) { - if (typedProgram.getCurrentClass().getCurrentMethod().isLocalVariableInMethod(name)) { + TypedClass currentClass = typedProgram.getCurrentClass(); + TypedMethod currentMethod = currentClass.getCurrentMethod(); + TypedConstructor currentConstructor = currentClass.getCurrentConstructor(); + + if (currentClass.isCurrentMethodPresent() && !currentClass.isCurrentConstructorPresent()) { + if (currentMethod.isLocalVariableInMethod(name)) { throw new RuntimeException("Variable " + name + " already declared"); } - typedProgram.getCurrentClass().getCurrentMethod().getLocalVariables().add(this); + currentMethod.getLocalVariables().add(this); return type; } - if (!typedProgram.getCurrentClass().isCurrentMethodPresent() && typedProgram.getCurrentClass().isCurrentConstructorPresent()) { - if (typedProgram.getCurrentClass().getCurrentConstructor().isLocalVariableInConstructor(name)) { + if (!currentClass.isCurrentMethodPresent() && currentClass.isCurrentConstructorPresent()) { + if (currentConstructor.isLocalVariableInConstructor(name)) { throw new RuntimeException("Variable " + name + " already declared"); } - typedProgram.getCurrentClass().getCurrentConstructor().getLocalVariables().add(this); + currentConstructor.getLocalVariables().add(this); return type; } throw new RuntimeException("not found method or constructor in class"); diff --git a/src/main/java/de/maishai/typedast/typedclass/TypedMain.java b/src/main/java/de/maishai/typedast/typedclass/TypedMain.java index 67c4671..aa49029 100644 --- a/src/main/java/de/maishai/typedast/typedclass/TypedMain.java +++ b/src/main/java/de/maishai/typedast/typedclass/TypedMain.java @@ -15,14 +15,14 @@ public class TypedMain implements TypedNode { private Type type = Type.VOID; private TypedMethod typedMethod; - public TypedMain(){ + public TypedMain() { typedMethod = new TypedMethod(); typedMethod.setName("main"); typedMethod.setReturnType(type); typedMethod.setTypedParameters(List.of(new TypedParameter("args", Type.REFERENCE("String[]")))); } - public void convertToTypedMethod(TypedProgram typedProgram, Class unTypedClass){ + public void convertToTypedMethod(TypedProgram typedProgram, Class unTypedClass) { typedMethod.setTypedBlock(new TypedBlock(typedProgram, unTypedClass.mainmeth())); } diff --git a/src/main/java/de/maishai/typedast/typedclass/TypedMethod.java b/src/main/java/de/maishai/typedast/typedclass/TypedMethod.java index 674f4e9..2048b53 100644 --- a/src/main/java/de/maishai/typedast/typedclass/TypedMethod.java +++ b/src/main/java/de/maishai/typedast/typedclass/TypedMethod.java @@ -1,6 +1,7 @@ package de.maishai.typedast.typedclass; import de.maishai.ast.records.Method; +import de.maishai.ast.records.Parameter; import de.maishai.typedast.*; import lombok.AllArgsConstructor; import lombok.Data; @@ -26,21 +27,21 @@ public class TypedMethod implements TypedNode { } public void convertToTypedMethod(TypedProgram typedProgram, Method unTypedMethod) { + TypedClass currentClass = typedProgram.getCurrentClass(); name = unTypedMethod.methodName(); returnType = unTypedMethod.type(); - for (var parameter : unTypedMethod.params()) { - TypedParameter typedParameter = new TypedParameter(typedProgram, parameter); + convertToTypedParameter(typedProgram, unTypedMethod.params()); + currentClass.checkMethodExists(this); + } + + private void convertToTypedParameter(TypedProgram typedProgram, List params) { + for (Parameter param : params) { + TypedParameter typedParameter = new TypedParameter(typedProgram, param); checkIfParameterExists(typedParameter.getParaName()); typedParameters.add(typedParameter); localVariables.add(new TypedLocalVariable(typedParameter.getParaName(), typedParameter.getType())); } - - typedProgram.getCurrentClass().getTypedMethods().stream().filter(method -> method.equals(this)).findFirst().ifPresentOrElse( - method -> { - throw new RuntimeException("Method " + name + " already exists"); - }, () -> { - }); } public void checkIfParameterExists(String parameterName) { @@ -49,6 +50,7 @@ public class TypedMethod implements TypedNode { } } + public void convertToTypedBlock(TypedProgram typedProgram, Method unTypedMethod) { typedBlock = new TypedBlock(typedProgram, unTypedMethod.block()); typeCheck(typedProgram); @@ -67,9 +69,10 @@ public class TypedMethod implements TypedNode { return isLocalVariablePresent(localVarName) || isParameterPresent(localVarName); } - public void deleteLocalVariableInMethod(String localVarName){ + public void deleteLocalVariableInMethod(String localVarName) { localVariables.removeIf(localVariable -> localVariable.getName().equals(localVarName)); } + public Type getLocalVariableType(String localVarName) { return localVariables.stream().filter(localVariable -> localVariable.getName().equals(localVarName)).findFirst().get().getType(); } @@ -117,7 +120,7 @@ public class TypedMethod implements TypedNode { public Type typeCheck(TypedProgram typedProgram) { if (returnType != Type.VOID && !checkReturn(typedBlock.getStmts())) { if (typedBlock.typeCheck(typedProgram).getKind() != returnType.getKind()) { - throw new RuntimeException("please use ´return´ correctly in the method " + name); + throw new RuntimeException("please use ´return´ correctly in the method " + name); } } return returnType; diff --git a/src/main/java/de/maishai/typedast/typedclass/TypedMethodCall.java b/src/main/java/de/maishai/typedast/typedclass/TypedMethodCall.java index 6f34518..8783a08 100644 --- a/src/main/java/de/maishai/typedast/typedclass/TypedMethodCall.java +++ b/src/main/java/de/maishai/typedast/typedclass/TypedMethodCall.java @@ -41,12 +41,17 @@ public class TypedMethodCall implements TypedExpression, TypedStatement { @Override public Type typeCheck(TypedProgram typedProgram) { + TypedClass currentClass = typedProgram.getCurrentClass(); String ownerChainName = null; + if (currentClass.isCurrentMainMethodPresent() && recipient.getRecursiveOwnerChain() == null) { + throw new RuntimeException("Main Method, is not allowed to have methods, they are not static"); + } + if (recipient.getRecursiveOwnerChain() != null) { ownerChainName = recipient.getRecursiveOwnerChain().getType().getReference(); } - if (!typedProgram.getCurrentClass().getClassName().equals(ownerChainName) && ownerChainName != null) { + if (!currentClass.getClassName().equals(ownerChainName) && ownerChainName != null) { Optional matchingMethod = findMatchingMethod(typedProgram.getTypedClass(ownerChainName), recipient.getName()); if (matchingMethod.isPresent()) { type = matchingMethod.get(); @@ -54,8 +59,8 @@ public class TypedMethodCall implements TypedExpression, TypedStatement { } } - if (typedProgram.getCurrentClass().isCurrentMethodPresent() || typedProgram.getCurrentClass().isCurrentConstructorPresent()) { - Optional matchingMethod = findMatchingMethod(typedProgram.getCurrentClass(), recipient.getName()); + if (currentClass.isCurrentMethodPresent() || currentClass.isCurrentConstructorPresent()) { + Optional matchingMethod = findMatchingMethod(currentClass, recipient.getName()); if (matchingMethod.isPresent()) { type = matchingMethod.get(); return type; diff --git a/src/main/java/de/maishai/typedast/typedclass/TypedNew.java b/src/main/java/de/maishai/typedast/typedclass/TypedNew.java index 0d30938..14adc82 100644 --- a/src/main/java/de/maishai/typedast/typedclass/TypedNew.java +++ b/src/main/java/de/maishai/typedast/typedclass/TypedNew.java @@ -35,29 +35,36 @@ public class TypedNew implements TypedExpression, TypedStatement { @Override public Type typeCheck(TypedProgram typedProgram) { + TypedClass currentClass = typedProgram.getCurrentClass(); if (typedProgram.isTypedClassPresent(type.getReference())) { return Type.REFERENCE(type.getReference()); } - for (var constructor : typedProgram.getCurrentClass().getTypedConstructors()) { + return findMatchingConstructorType(typedProgram, args); + } + + private Type findMatchingConstructorType(TypedProgram typedProgram, List args) { + TypedClass currentClass = typedProgram.getCurrentClass(); + List constructors = currentClass.getTypedConstructors(); + for (var constructor : constructors) { if (constructor.getTypedParameters().size() == args.size()) { boolean valid = true; for (int i = 0; i < args.size(); i++) { - if (!constructor.getTypedParameters().get(i).getType().equals(args.get(i).typeCheck(typedProgram))) { + boolean typeOfPara = constructor.getTypedParameters().get(i).getType().equals(args.get(i).typeCheck(typedProgram)); + if (!typeOfPara) { valid = false; break; } } if (valid) { - return Type.REFERENCE(typedProgram.getCurrentClass().getClassName()); + return Type.REFERENCE(currentClass.getClassName()); } } } throw new RuntimeException("No matching constructor found"); } - @Override public void codeGen(MethodContext ctx) { ctx.getMv().visitTypeInsn(Opcodes.NEW, type.getReference()); diff --git a/src/main/java/de/maishai/typedast/typedclass/TypedProgram.java b/src/main/java/de/maishai/typedast/typedclass/TypedProgram.java index 8a8571e..e7daa7e 100644 --- a/src/main/java/de/maishai/typedast/typedclass/TypedProgram.java +++ b/src/main/java/de/maishai/typedast/typedclass/TypedProgram.java @@ -47,9 +47,11 @@ public class TypedProgram { public boolean isClassWithNamePresent(String className) { return typedClasses.stream().anyMatch(clas -> clas.getClassName().equals(className)); } + public Type getTypeOfFieldNameInClass(String className, String fieldName) { return typedClasses.stream().filter(clas -> clas.getClassName().equals(className)).findFirst().get().getFieldType(fieldName); } + public TypedClass getTypedClass(String className) { return typedClasses.stream().filter(clas -> clas.getClassName().equals(className)).findFirst().get(); } @@ -71,7 +73,7 @@ public class TypedProgram { if (this == obj) return true; if (obj == null || getClass() != obj.getClass()) return false; TypedProgram other = (TypedProgram) obj; - if(typedClasses.equals(other.typedClasses) && + if (typedClasses.equals(other.typedClasses) && (currentClass == null && other.currentClass == null || currentClass.equals(other.currentClass))) { return true; diff --git a/src/main/java/de/maishai/typedast/typedclass/TypedReturn.java b/src/main/java/de/maishai/typedast/typedclass/TypedReturn.java index 4502d05..b3f180a 100644 --- a/src/main/java/de/maishai/typedast/typedclass/TypedReturn.java +++ b/src/main/java/de/maishai/typedast/typedclass/TypedReturn.java @@ -36,13 +36,16 @@ public class TypedReturn implements TypedStatement { @Override public Type typeCheck(TypedProgram typedProgram) { - if (typedProgram.getCurrentClass().isCurrentMethodPresent()) { - if (typedProgram.getCurrentClass().getCurrentMethod().getReturnType().getKind() != this.type.getKind()) { + TypedClass currentClass = typedProgram.getCurrentClass(); + TypedMethod currentMethod = currentClass.getCurrentMethod(); + + if (currentClass.isCurrentMethodPresent()) { + if (currentMethod.getReturnType().getKind() != this.type.getKind()) { StringBuilder exp = new StringBuilder(); exp.append("\nMismatched return type: "); - exp.append("\nExpected: ").append(typedProgram.getCurrentClass().getCurrentMethod().getReturnType().getKind()); + exp.append("\nExpected: ").append(currentMethod.getReturnType().getKind()); exp.append("\nActual: ").append(this.type.getKind()); - exp.append("\nMethod name: ").append(typedProgram.getCurrentClass().getCurrentMethod().getName()); + exp.append("\nMethod name: ").append(currentMethod.getName()); throw new RuntimeException(exp.toString()); } }