diff --git a/src/main/java/abstractSyntaxTree/Class/MethodDecl.java b/src/main/java/abstractSyntaxTree/Class/MethodDecl.java index da253fb..54f38a9 100644 --- a/src/main/java/abstractSyntaxTree/Class/MethodDecl.java +++ b/src/main/java/abstractSyntaxTree/Class/MethodDecl.java @@ -77,18 +77,31 @@ public class MethodDecl implements Node { HashMap classFields = typeContext.get(classThatContainsMethod); //Set the fields of the class + boolean fieldFound = false; for (Map.Entry entry : classFields.entrySet()) { String fieldName = entry.getKey(); for (FieldDecl field : fieldDecls) { if (field.identifier.equals(fieldName)) { mv.visitVarInsn(Opcodes.ALOAD, 0); - field.expression.codeGen(mv, localVars, typeContext, methodContext); + if (field.expression != null) { + field.expression.codeGen(mv, localVars, typeContext, methodContext); + } else { + // If the field is not initialized, we need to load a default value onto the stack + switch (field.type) { + case "int", "boolean", "char" -> mv.visitInsn(Opcodes.ICONST_0); + default -> mv.visitInsn(Opcodes.ACONST_NULL); + } + } descriptor = getFieldDescriptor(field.type); mv.visitFieldInsn(Opcodes.PUTFIELD, classThatContainsMethod, fieldName, descriptor); - } else { - throw new Exception("Field " + fieldName + " not found"); + fieldFound = true; + break; } } + + if (!fieldFound){ + throw new Exception("Field " + fieldName + " not found"); + } } //Load the parameters onto the stack diff --git a/src/main/java/abstractSyntaxTree/StatementExpression/AssignStatementExpression.java b/src/main/java/abstractSyntaxTree/StatementExpression/AssignStatementExpression.java index 0f40fca..5556dcb 100644 --- a/src/main/java/abstractSyntaxTree/StatementExpression/AssignStatementExpression.java +++ b/src/main/java/abstractSyntaxTree/StatementExpression/AssignStatementExpression.java @@ -67,11 +67,6 @@ public class AssignStatementExpression extends AbstractType implements IExpressi @Override public void codeGen(MethodVisitor mv, LinkedHashMap localVars, HashMap> typeContext, HashMap>> methodContext) throws Exception { - //TODO: Do we need the value on the stack after assigning it? - //TODO: WE do not differentiate between InstanceVar and FieldVar - - // Call the codeGen on the right expression which will push the value of the right expression onto the stack - right.codeGen(mv, localVars, typeContext, methodContext); if (left instanceof LocalVarIdentifier) { LocalVarIdentifier localVar = (LocalVarIdentifier) left; @@ -89,10 +84,25 @@ public class AssignStatementExpression extends AbstractType implements IExpressi } if (index == -1) { - throw new Exception("Variable " + varName + " not found"); + String fieldType = typeContext.get(thisClass).get(varName); + if (fieldType != null) { + // Load "this" onto the stack + mv.visitVarInsn(Opcodes.ALOAD, 0); + // Call the codeGen on the right expression which will push the value of the right expression onto the stack + right.codeGen(mv, localVars, typeContext, methodContext); + // Get the field descriptor + String descriptor = getFieldDescriptor(fieldType, typeContext); + // Store the value in the field + mv.visitFieldInsn(Opcodes.PUTFIELD, thisClass, varName, descriptor); + return; + } else { + throw new Exception("Variable " + varName + " not found"); + } } String type = localVars.get(localVar.getIdentifier()); + // Call the codeGen on the right expression which will push the value of the right expression onto the stack + right.codeGen(mv, localVars, typeContext, methodContext); switch (type) { case "int", "char", "boolean": mv.visitVarInsn(Opcodes.ISTORE, index); @@ -108,35 +118,41 @@ public class AssignStatementExpression extends AbstractType implements IExpressi // Load "this" onto the stack mv.visitVarInsn(Opcodes.ALOAD, 0); - // Duplicate the top of the stack as we'll need it for both the PUTFIELD and subsequent expressions - mv.visitInsn(Opcodes.DUP_X1); + // Call the codeGen on the right expression which will push the value of the right expression onto the stack + right.codeGen(mv, localVars, typeContext, methodContext); // Get the field information String fieldType = typeContext.get(instVar.thisClass).get(instVar.fieldName); - StringBuilder descriptor = new StringBuilder(); - - switch (fieldType) { - case "int": - descriptor.append("I"); - break; - case "boolean": - descriptor.append("Z"); - break; - default: - String fullReturnType = typeContext.get(instVar.thisClass).get(instVar.fieldName); - - // If it is a class reference replace the "." with "/" and return it - if (fieldType.contains(".")) fullReturnType = fullReturnType.replaceAll("\\.", "/"); - if (fullReturnType != null) descriptor.append("L").append(fullReturnType).append(";"); - break; - } + // Get the field descriptor + String descriptor = getFieldDescriptor(fieldType, typeContext); // Store the value in the field - mv.visitFieldInsn(Opcodes.PUTFIELD, instVar.thisClass, instVar.fieldName, descriptor.toString()); + mv.visitFieldInsn(Opcodes.PUTFIELD, instVar.thisClass, instVar.fieldName, descriptor); } } + private String getFieldDescriptor(String type, HashMap> typeContext) { + StringBuilder descriptor = new StringBuilder(); + switch (type) { + case "int": + return "I"; + case "boolean": + return "Z"; + case "char": + return "C"; + default: { + String fullReturnType = typeContext.get(instVar.thisClass).get(instVar.fieldName); + + // If it is a class reference replace the "." with "/" and return it + if (type.contains(".")) fullReturnType = fullReturnType.replaceAll("\\.", "/"); + if (fullReturnType != null) descriptor.append("L").append(fullReturnType).append(";"); + return descriptor.toString(); + } + } + } + + @Override public boolean equals(Object o) { if (this == o) return true;