diff --git a/src/main/java/abstractSyntaxTree/Expression/SubReceiver.java b/src/main/java/abstractSyntaxTree/Expression/SubReceiver.java index 1b58259..1c40175 100644 --- a/src/main/java/abstractSyntaxTree/Expression/SubReceiver.java +++ b/src/main/java/abstractSyntaxTree/Expression/SubReceiver.java @@ -6,7 +6,7 @@ import abstractSyntaxTree.StatementExpression.NewStatementExpression; import java.util.Objects; public class SubReceiver implements Node { - boolean thisExpression; + public boolean thisExpression; public NewStatementExpression newStatementExpression; public String identifier; diff --git a/src/main/java/abstractSyntaxTree/StatementExpression/AssignStatementExpression.java b/src/main/java/abstractSyntaxTree/StatementExpression/AssignStatementExpression.java index 7a8f033..07f311d 100644 --- a/src/main/java/abstractSyntaxTree/StatementExpression/AssignStatementExpression.java +++ b/src/main/java/abstractSyntaxTree/StatementExpression/AssignStatementExpression.java @@ -85,7 +85,7 @@ public class AssignStatementExpression extends AbstractType implements IExpressi int counter = 0; for (String key : localVars.keySet()) { if (key.equals(varName)) { - index = counter+1; + index = counter + 1; break; } counter++; @@ -123,6 +123,8 @@ public class AssignStatementExpression extends AbstractType implements IExpressi } else if (left instanceof InstVarExpression) { instVar = (InstVarExpression) left; + boolean isLocal = false; + // Load the reference onto the stack // Determine if the reference is this or another object if (instVar.receivers.get(0).identifier != null) { @@ -140,25 +142,157 @@ public class AssignStatementExpression extends AbstractType implements IExpressi throw new Exception("Variable " + instVar.receivers.get(0).identifier + " not found"); } mv.visitVarInsn(Opcodes.ALOAD, index); + isLocal = true; } else { // 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); + //right.codeGen(mv, localVars, typeContext, methodContext); - // Get the field information - String fieldType = typeContext.get(instVar.thisClass).get(instVar.fieldName); - // Get the field descriptor - String descriptor = getFieldDescriptor(fieldType, typeContext, instVar.fieldName, instVar.thisClass); + //Now that the base ref is on the stack, I need to get the next field(s) and store the value in the last field - // Store the value in the field - mv.visitFieldInsn(Opcodes.PUTFIELD, instVar.thisClass, instVar.fieldName, descriptor); + String typeOfPrevious = ""; + String currentType = ""; + if (instVar.receivers.size() > 0) { + for (int i = 0; i < instVar.receivers.size(); i++) { + + if (i == 0) { + + //Check if the chain is longer than 1 + // If it is not, then we can directly store the value in the field + // If not we have to load the reference of the field on the stack + if (instVar.receivers.size() < 2) { + // Chain is only 1 long, so we can call PUTFIELD directly + + //Load the value of the right expression on the stack + right.codeGen(mv, localVars, typeContext, methodContext); + + if (isLocal) { + typeOfPrevious = localVars.get(instVar.receivers.get(i).identifier); + } else { + typeOfPrevious = typeContext.get(thisClass).get(instVar.receivers.get(i).identifier); + if (typeOfPrevious == null) { + typeOfPrevious = thisClass; + } + } + + currentType = typeContext.get(typeOfPrevious).get(instVar.fieldName); + + String descriptor = getFieldDescriptor(currentType, typeContext, instVar.fieldName, thisClass); + mv.visitFieldInsn(Opcodes.PUTFIELD, typeOfPrevious, instVar.fieldName, descriptor); + continue; + } else { + + if (isLocal) { + currentType = localVars.get(instVar.receivers.get(i).identifier); + } else { + currentType = typeContext.get(thisClass).get(instVar.receivers.get(i).identifier); + } + + String descriptor = getFieldDescriptor(currentType, typeContext, instVar.receivers.get(i).identifier, thisClass); + mv.visitFieldInsn(Opcodes.GETFIELD, thisClass, instVar.receivers.get(i).identifier, descriptor); + typeOfPrevious = currentType; + continue; + } + } + //Now we have to implement the logic for the following fields in the chain as the above code + // only handles the first field in the chain + + // For the following fields I only have to call GETFIELD so I load the next reference onto the stack + // The fields must be present in "typeOfPrevious" + + currentType = typeContext.get(typeOfPrevious).get(instVar.receivers.get(i).identifier); + String descriptor = getFieldDescriptor(currentType, typeContext, instVar.receivers.get(i).identifier, typeOfPrevious); + mv.visitFieldInsn(Opcodes.GETFIELD, typeOfPrevious, instVar.receivers.get(i).identifier, descriptor); + typeOfPrevious = currentType; + } + + // Now we have the reference of the last field in the chain on the stack + if (instVar.receivers.size() > 1) { + // We can store the value of the right expression in this field + right.codeGen(mv, localVars, typeContext, methodContext); + + currentType = typeContext.get(typeOfPrevious).get(instVar.fieldName); + String descriptor = getFieldDescriptor(currentType, typeContext, instVar.fieldName, typeOfPrevious); + mv.visitFieldInsn(Opcodes.PUTFIELD, typeOfPrevious, instVar.fieldName, descriptor); + } + + } else { + //This is finished and right + // It's for when a field is accessed directly and without a "this." + + //Load the value of the right expression on the stack + right.codeGen(mv, localVars, typeContext, methodContext); + + // Get the field information + String fieldType = typeContext.get(instVar.thisClass).get(instVar.fieldName); + + // Get the field descriptor + String descriptor = getFieldDescriptor(fieldType, typeContext, instVar.fieldName, instVar.thisClass); + + // Store the value in the field + mv.visitFieldInsn(Opcodes.PUTFIELD, instVar.thisClass, instVar.fieldName, descriptor); + } } } + + /* + // Field is called with "this.xxx" + if (instVar.receivers.get(0).thisExpression) { + + // If the chain is only 1 long we can directly store the value in the field + // If not we have to load the reference of the field on the stack + if(instVar.receivers.size() > 1) { + // If first receiver is not this check local then fields of thisClass + if (isLocal) { + currentType = localVars.get(instVar.receivers.get(i).identifier); + } else { + currentType = typeContext.get(thisClass).get(instVar.receivers.get(i).identifier); + } + + currentType = typeContext.get(thisClass).get(instVar.fieldName); + String descriptor = getFieldDescriptor(currentType, typeContext, instVar.fieldName, thisClass); + mv.visitFieldInsn(Opcodes.GETFIELD, thisClass, instVar.fieldName, descriptor); + continue; + } else { + // Chain is only 1 long, so we can call PUTFIELD directly + + //Load the value of the right expression on the stack + right.codeGen(mv, localVars, typeContext, methodContext); + + currentType = typeContext.get(thisClass).get(instVar.fieldName); + String descriptor = getFieldDescriptor(currentType, typeContext, instVar.fieldName, thisClass); + mv.visitFieldInsn(Opcodes.PUTFIELD, thisClass, instVar.fieldName, descriptor); + continue; + } + } + + + // If first receiver is not this check local then fields of thisClass + if (isLocal) { + currentType = localVars.get(instVar.receivers.get(i).identifier); + } else { + currentType = typeContext.get(thisClass).get(instVar.receivers.get(i).identifier); + } + + currentType = typeContext.get(typeOfPrevious).get(instVar.fieldName); + String descriptor = getFieldDescriptor(currentType, typeContext, instVar.fieldName, typeOfPrevious); + mv.visitFieldInsn(Opcodes.GETFIELD, thisClass, instVar.fieldName, descriptor); + continue; + } + + currentType = typeContext.get(typeOfPrevious).get(instVar.receivers.get(i).identifier); + String descriptor = getFieldDescriptor(currentType, typeContext, instVar.receivers.get(i).identifier, typeOfPrevious); + mv.visitFieldInsn(Opcodes.GETFIELD, typeOfPrevious, instVar.receivers.get(i).identifier, descriptor); + typeOfPrevious = currentType; + } */ + + private String getFieldDescriptor(String type, HashMap> typeContext, String varName, String classToSearchFieldIn) { StringBuilder descriptor = new StringBuilder(); switch (type) {