diff --git a/src/main/java/de/maishai/Compiler.java b/src/main/java/de/maishai/Compiler.java index 1f1ebeb..08a70a1 100644 --- a/src/main/java/de/maishai/Compiler.java +++ b/src/main/java/de/maishai/Compiler.java @@ -99,7 +99,8 @@ public class Compiler { public static void main(String[] args) { generateByteCodeFileFromFile(List.of("src/main/resources/JavaTestfiles/ClassWithConstructor.java", - "src/main/resources/JavaTestfiles/ClassWithConstructorAndMethodCall.java"), - List.of("ClassWithConstructor","ClassWithConstructorAndMethodCall")); + "src/main/resources/JavaTestfiles/ClassWithConstructorAndMethodCall.java", + "src/main/resources/JavaTestfiles/ComplexClass.java"), + List.of("ClassWithConstructor","ClassWithConstructorAndMethodCall","ComplexClass")); } } diff --git a/src/main/java/de/maishai/ExpressionGenerator.java b/src/main/java/de/maishai/ExpressionGenerator.java index 3701aec..ce6a224 100644 --- a/src/main/java/de/maishai/ExpressionGenerator.java +++ b/src/main/java/de/maishai/ExpressionGenerator.java @@ -123,7 +123,7 @@ public class ExpressionGenerator extends DecafBaseVisitor { DecafParser.RecipientContext ctx = ctxList.get(lastElement); ctxList.remove(lastElement); if (ctx.id() != null) { - return new FieldVarAccess(false, generateRecursiveOwnerChain(ctxList, recipient), ctx.id().IDENTIFIER().getText()); + return new FieldVarAccess(true, generateRecursiveOwnerChain(ctxList, recipient), ctx.id().IDENTIFIER().getText()); } if (ctx.methName() != null) { List args = new ArrayList<>(); diff --git a/src/main/java/de/maishai/typedast/Help/TypedExpressionHelp.java b/src/main/java/de/maishai/typedast/Help/TypedExpressionHelp.java index bbd8072..2cef079 100644 --- a/src/main/java/de/maishai/typedast/Help/TypedExpressionHelp.java +++ b/src/main/java/de/maishai/typedast/Help/TypedExpressionHelp.java @@ -34,7 +34,7 @@ public class TypedExpressionHelp { } else if (expression instanceof MethodCall methodCall) { TypedMethodCall typedMethodCall = new TypedMethodCall( typedProgram, methodCall); - typedMethodCall.typeCheck( typedProgram); + typedMethodCall.typeCheck(typedProgram); return typedMethodCall; } else if (expression instanceof New newStmt) { diff --git a/src/main/java/de/maishai/typedast/typedclass/TypedAssignment.java b/src/main/java/de/maishai/typedast/typedclass/TypedAssignment.java index 556627e..16143fd 100644 --- a/src/main/java/de/maishai/typedast/typedclass/TypedAssignment.java +++ b/src/main/java/de/maishai/typedast/typedclass/TypedAssignment.java @@ -31,20 +31,24 @@ public class TypedAssignment implements TypedStatement { public Type typeCheck(TypedProgram typedProgram) { Type typeLeft = null; - if (typedProgram.getCurrentClass().isThereField(location.getName())) { + if (typedProgram.getCurrentClass().isThereField(location.getName()) && location.getField()) { typeLeft = typedProgram.getCurrentClass().getFieldType(location.getName()); } else { if (typedProgram.getCurrentClass().isCurrentMethodPresent() && !typedProgram.getCurrentClass().isCurrentConstructorPresent()) { if (typedProgram.getCurrentClass().getCurrentMethod().isLocalVariableInMethod(location.getName())) { typeLeft = typedProgram.getCurrentClass().getCurrentMethod().getLocalVariableType(location.getName()); - } else { + } else if(typedProgram.getCurrentClass().isThereField(location.getName())){ + typeLeft = typedProgram.getCurrentClass().getFieldType(location.getName()); + }else { throw new RuntimeException("Variable " + location.getName() + " not declared in method"); } } if (!typedProgram.getCurrentClass().isCurrentMethodPresent() && typedProgram.getCurrentClass().isCurrentConstructorPresent()) { if (typedProgram.getCurrentClass().getCurrentConstructor().isLocalVariableInConstructor(location.getName())) { typeLeft = typedProgram.getCurrentClass().getCurrentConstructor().getLocalVariableType(location.getName()); - } else { + }else if(typedProgram.getCurrentClass().isThereField(location.getName())){ + typeLeft = typedProgram.getCurrentClass().getFieldType(location.getName()); + }else { throw new RuntimeException("Variable " + location.getName() + " not declared in constructor"); } } diff --git a/src/main/java/de/maishai/typedast/typedclass/TypedClass.java b/src/main/java/de/maishai/typedast/typedclass/TypedClass.java index 94dc6f9..a994fcb 100644 --- a/src/main/java/de/maishai/typedast/typedclass/TypedClass.java +++ b/src/main/java/de/maishai/typedast/typedclass/TypedClass.java @@ -28,13 +28,11 @@ public class TypedClass implements TypedNode { private TypedConstructor currentConstructor; private Type type; - public TypedClass(TypedProgram typedProgram, Class c) { + public TypedClass(Class c) { className = c.classname(); type = Type.REFERENCE(className); - convertMethodsAndConstructorsAndFields(typedProgram, c); } - public boolean isParameterNameInCurrentConstructor(String parameterName) { if (currentConstructor == null) { return false; @@ -47,7 +45,7 @@ public class TypedClass implements TypedNode { return false; } - public void convertMethodsAndConstructorsAndFields(TypedProgram typedProgram, Class c){ + public void convertMethodsAndConstructorsAndFields(TypedProgram typedProgram, Class c) { // Am Anfang werden die Attribute, die Konstruktoren und Methoden in die jeweilige Liste eingefügt. // damit die Methoden verwendet werden können, bevor deren Blöcke ausgeführt werden for (Declaration declaration : c.fieldDeclarations()) { @@ -62,7 +60,7 @@ public class TypedClass implements TypedNode { } } - public void covertBlocksOfConstructorsAndMethods(TypedProgram typedProgram, Class c){ + public void covertBlocksOfConstructorsAndMethods(TypedProgram typedProgram, Class c) { // Hier werden die Blöcke der Konstruktoren ausgeführt int i = 0; for (Constructor constructor : c.constructors()) { diff --git a/src/main/java/de/maishai/typedast/typedclass/TypedConstructor.java b/src/main/java/de/maishai/typedast/typedclass/TypedConstructor.java index 27c188a..f8ec43a 100644 --- a/src/main/java/de/maishai/typedast/typedclass/TypedConstructor.java +++ b/src/main/java/de/maishai/typedast/typedclass/TypedConstructor.java @@ -53,11 +53,19 @@ public class TypedConstructor implements TypedNode { name = unTypedConstructor.className(); for (Parameter param : unTypedConstructor.params()) { - typedParameters.add(new TypedParameter(typedProgram, param)); + 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) { + if (typedParameters.stream().anyMatch(parameter -> parameter.getParaName().equals(paraName))) { + throw new RuntimeException("Parameter " + paraName + " already exists"); + } + } public void convertToBlock(TypedProgram typedProgram, Constructor unTypedConstructor) { this.typedBlock = new TypedBlock(typedProgram, unTypedConstructor.block()); typeCheck(typedProgram); diff --git a/src/main/java/de/maishai/typedast/typedclass/TypedDeclaration.java b/src/main/java/de/maishai/typedast/typedclass/TypedDeclaration.java index 4d9feb1..587df2d 100644 --- a/src/main/java/de/maishai/typedast/typedclass/TypedDeclaration.java +++ b/src/main/java/de/maishai/typedast/typedclass/TypedDeclaration.java @@ -9,7 +9,6 @@ import lombok.NoArgsConstructor; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.Opcodes; -import static de.maishai.typedast.Type.Kind.REFERENCE; @Data @AllArgsConstructor @@ -30,27 +29,20 @@ public final class TypedDeclaration implements TypedNode { @Override public Type typeCheck(TypedProgram typedProgram) { + if(type.getReference() != null && !typedProgram.getCurrentClass().getClassName().equals(type.getReference())) { + if (!typedProgram.isTypedClassPresent(type.getReference())) { + throw new RuntimeException("Type " + type.getReference() + " not found"); + } + } + if (typedProgram.getCurrentClass().isThereField(name)) { throw new RuntimeException("Field " + name + " already declared"); } - if (type.getKind() == REFERENCE) { - if (!type.getReference().equals(typedProgram.getCurrentClass().getClassName())) { - throw new RuntimeException("Field " + name + " has wrong type"); - } - - } return type; } - /* - public void codeGen(MethodVisitor mv, MethodContext ctx) { - System.out.println("Generating code for local variable " + name); - int index = ctx.addVariable(name); - mv.visitLocalVariable(name, type.getDescriptor(), null, ctx.getStartLabel(), ctx.getEndLabel(), index); - } - */ public void codeGen(ClassWriter cw) { int access = Opcodes.ACC_PUBLIC; // laut Andi ist es ok, dass alle Felder public sind cw.visitField(access, name, type.getDescriptor(), null, null).visitEnd(); diff --git a/src/main/java/de/maishai/typedast/typedclass/TypedFieldVarAccess.java b/src/main/java/de/maishai/typedast/typedclass/TypedFieldVarAccess.java index 2030d52..3b29ade 100644 --- a/src/main/java/de/maishai/typedast/typedclass/TypedFieldVarAccess.java +++ b/src/main/java/de/maishai/typedast/typedclass/TypedFieldVarAccess.java @@ -34,7 +34,10 @@ public class TypedFieldVarAccess implements TypedExpression { if (field) { if (typedProgram.getCurrentClass().isThereField(name)) { type = typedProgram.getCurrentClass().getFieldType(name); - return typedProgram.getCurrentClass().getFieldType(name); + return type; + }else if(recursiveOwnerChain instanceof TypedFieldVarAccess typedFieldVarAccess){ + type = typedProgram.getCurrentClass().getFieldType(typedFieldVarAccess.getName()); + return type; }else{ throw new RuntimeException("Field " + name + " not declared "); } diff --git a/src/main/java/de/maishai/typedast/typedclass/TypedMethod.java b/src/main/java/de/maishai/typedast/typedclass/TypedMethod.java index 5b4eb3e..4bb93d9 100644 --- a/src/main/java/de/maishai/typedast/typedclass/TypedMethod.java +++ b/src/main/java/de/maishai/typedast/typedclass/TypedMethod.java @@ -28,7 +28,10 @@ public class TypedMethod implements TypedNode { name = unTypedMethod.methodName(); returnType = unTypedMethod.type(); for (var parameter : unTypedMethod.params()) { - typedParameters.add(new TypedParameter(typedProgram, parameter)); + TypedParameter typedParameter = new TypedParameter(typedProgram, parameter); + 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( @@ -37,6 +40,11 @@ public class TypedMethod implements TypedNode { }, () -> { }); } + public void checkIfParameterExists(String parameterName) { + if (typedParameters.stream().anyMatch(parameter -> parameter.getParaName().equals(parameterName))) { + throw new RuntimeException("Parameter " + parameterName + " already exists"); + } + } public void convertToTypedBlock(TypedProgram typedProgram, Method unTypedMethod) { typedBlock = new TypedBlock(typedProgram, unTypedMethod.block()); diff --git a/src/main/java/de/maishai/typedast/typedclass/TypedMethodCall.java b/src/main/java/de/maishai/typedast/typedclass/TypedMethodCall.java index e3fc6c9..21fe9d7 100644 --- a/src/main/java/de/maishai/typedast/typedclass/TypedMethodCall.java +++ b/src/main/java/de/maishai/typedast/typedclass/TypedMethodCall.java @@ -8,10 +8,10 @@ import lombok.NoArgsConstructor; import java.util.ArrayList; import java.util.List; +import java.util.Optional; import static de.maishai.typedast.Help.TypedExpressionHelp.convertExpression; -//TODO: test this after fixing error from parser @Data @NoArgsConstructor @@ -26,38 +26,60 @@ public class TypedMethodCall implements TypedExpression, TypedStatement { public void convertToTypedMethodCall(TypedProgram typedProgram, MethodCall unTypedMethodCall) { recipient = new TypedFieldVarAccess(typedProgram, unTypedMethodCall.recipient()); - for (Expression arg : unTypedMethodCall.args()) { - args.add(convertExpression(typedProgram, arg)); - } + recipient.typeCheck(typedProgram); + for (Expression arg : unTypedMethodCall.args()) { + args.add(convertExpression(typedProgram, arg)); + } } @Override public Type typeCheck(TypedProgram typedProgram) { - if (typedProgram.getCurrentClass().isCurrentMethodPresent() || typedProgram.getCurrentClass().isCurrentConstructorPresent()) { + String ownerChainName = null; + if (recipient.getRecursiveOwnerChain() != null) { + ownerChainName = recipient.getRecursiveOwnerChain().getType().getReference(); + } - List methods = typedProgram.getCurrentClass().getTypedMethods().stream() - .filter(method -> method.getName().equals(recipient.getName())) - .toList(); - - for (TypedMethod method : methods) { - if (method.getTypedParameters().size() == args.size()) { - boolean allMatch = true; - for (int i = 0; i < args.size(); i++) { - if (!args.get(i).typeCheck(typedProgram).equals(method.getTypedParameters().get(i).getType())) { - allMatch = false; - break; - } - } - if (allMatch) { - type = method.getReturnType(); - return type; - } - } + if (!typedProgram.getCurrentClass().getClassName().equals(ownerChainName) && ownerChainName != null) { + Optional matchingMethod = findMatchingMethod(typedProgram.getTypedClass(ownerChainName), recipient.getName()); + if (matchingMethod.isPresent()) { + type = matchingMethod.get(); + return type; } } + + if (typedProgram.getCurrentClass().isCurrentMethodPresent() || typedProgram.getCurrentClass().isCurrentConstructorPresent()) { + Optional matchingMethod = findMatchingMethod(typedProgram.getCurrentClass(), recipient.getName()); + if (matchingMethod.isPresent()) { + type = matchingMethod.get(); + return type; + } + } + throw new RuntimeException("Method not found"); } + public Optional findMatchingMethod(TypedClass ownerChain, String methodName) { + List methods = ownerChain.getTypedMethods().stream() + .filter(method -> method.getName().equals(methodName)) + .toList(); + + for (TypedMethod method : methods) { + if (method.getTypedParameters().size() == args.size()) { + boolean allMatch = true; + for (int i = 0; i < args.size(); i++) { + if (!args.get(i).getType().equals(method.getTypedParameters().get(i).getType())) { + allMatch = false; + break; + } + } + if (allMatch) { + return Optional.of(method.getReturnType()); + } + } + } + + return Optional.empty(); + } @Override public void codeGen(MethodContext ctx) { diff --git a/src/main/java/de/maishai/typedast/typedclass/TypedNew.java b/src/main/java/de/maishai/typedast/typedclass/TypedNew.java index 6b8f322..185e40f 100644 --- a/src/main/java/de/maishai/typedast/typedclass/TypedNew.java +++ b/src/main/java/de/maishai/typedast/typedclass/TypedNew.java @@ -28,6 +28,11 @@ public class TypedNew implements TypedExpression, TypedStatement { @Override public Type typeCheck(TypedProgram typedProgram) { + + if(typedProgram.isTypedClassPresent(type.getReference())){ + return Type.REFERENCE(type.getReference()); + } + for (var constructor : typedProgram.getCurrentClass().getTypedConstructors()) { if (constructor.getTypedParameters().size() == args.size()) { boolean valid = true; diff --git a/src/main/java/de/maishai/typedast/typedclass/TypedProgram.java b/src/main/java/de/maishai/typedast/typedclass/TypedProgram.java index 1e52857..e21c9ba 100644 --- a/src/main/java/de/maishai/typedast/typedclass/TypedProgram.java +++ b/src/main/java/de/maishai/typedast/typedclass/TypedProgram.java @@ -19,10 +19,14 @@ public class TypedProgram { public void startConversion(Program program) { + for(var clas : program.classes()){ + typedClasses.add(new TypedClass(clas)); + } + int k = 0; for (var clas : program.classes()) { enterCurrentClass(typedClasses.get(k)); - typedClasses.add(new TypedClass(this, clas)); + typedClasses.get(k).convertMethodsAndConstructorsAndFields(this, clas); exitCurrentClass(); k++; } @@ -39,9 +43,8 @@ public class TypedProgram { public TypedClass getTypedClass(String className) { return typedClasses.stream().filter(clas -> clas.getClassName().equals(className)).findFirst().get(); } - - public boolean isCurrentClassPresent() { - return currentClass != null; + public boolean isTypedClassPresent(String className) { + return typedClasses.stream().anyMatch(clas -> clas.getClassName().equals(className)); } public void enterCurrentClass(TypedClass clas) {