Added missing thisClass setters as already discussed during the meeting.

Also fixed chaining of InstVar and the bugs it created in MethodCallStatementExpression
This commit is contained in:
Jochen Seyfried 2024-07-03 20:56:01 +02:00
parent 1dd405a00f
commit 82384886c6
5 changed files with 186 additions and 32 deletions

View File

@ -16,14 +16,14 @@ import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
public class InstVarExpression extends AbstractType implements IExpression{ public class InstVarExpression extends AbstractType implements IExpression {
public String thisClass; public String thisClass;
public List<SubReceiver> receivers; public List<SubReceiver> receivers;
public List<ReceivingMethod> receivingMethods; public List<ReceivingMethod> receivingMethods;
public String fieldName; public String fieldName;
public InstVarExpression(List<SubReceiver> receivers, List<ReceivingMethod> receivingMethods, String fieldName){ public InstVarExpression(List<SubReceiver> receivers, List<ReceivingMethod> receivingMethods, String fieldName) {
this.receivers = receivers; this.receivers = receivers;
this.receivingMethods = receivingMethods; this.receivingMethods = receivingMethods;
this.fieldName = fieldName; this.fieldName = fieldName;
@ -32,7 +32,7 @@ public class InstVarExpression extends AbstractType implements IExpression{
@Override @Override
public TypeCheckResult typeCheck(HashMap<String, HashMap<String, HashMap<String, ParameterList>>> methodContext, HashMap<String, HashMap<String, String>> typeContext, HashMap<String, String> localVars) throws TypeCheckException { public TypeCheckResult typeCheck(HashMap<String, HashMap<String, HashMap<String, ParameterList>>> methodContext, HashMap<String, HashMap<String, String>> typeContext, HashMap<String, String> localVars) throws TypeCheckException {
String typeOfSubreceiver = ""; String typeOfSubreceiver = "";
if(receivers.get(0).identifier != null) { if (receivers.get(0).identifier != null) {
String subreceiver = receivers.get(0).identifier; String subreceiver = receivers.get(0).identifier;
typeOfSubreceiver = localVars.get(subreceiver); typeOfSubreceiver = localVars.get(subreceiver);
if (typeOfSubreceiver == null) if (typeOfSubreceiver == null)
@ -45,7 +45,7 @@ public class InstVarExpression extends AbstractType implements IExpression{
} }
} }
}else { } else {
typeOfSubreceiver = thisClass; typeOfSubreceiver = thisClass;
} }
@ -63,34 +63,161 @@ public class InstVarExpression extends AbstractType implements IExpression{
// typeContext: (ClassName, (FieldName, FieldType)) // typeContext: (ClassName, (FieldName, FieldType))
public void codeGen(MethodVisitor mv, LinkedHashMap<String, String> localVars, HashMap<String, HashMap<String, String>> typeContext, HashMap<String, HashMap<String, HashMap<String, ParameterList>>> methodContext) throws Exception { public void codeGen(MethodVisitor mv, LinkedHashMap<String, String> localVars, HashMap<String, HashMap<String, String>> typeContext, HashMap<String, HashMap<String, HashMap<String, ParameterList>>> methodContext) throws Exception {
// Load "this" onto the stack // Load "this" onto the stack
String typeOfReciever = "";
String descriptor = "";
String classOfField = "";
// Determine if the reference is this or not // Determine if the reference is this or not
if (this.receivers.get(0).identifier != null) { if (this.receivers.get(0).identifier != null) {
for (int i = 0; i < receivers.size(); i++) {
if (i == 0) {
// Load the local variable onto the stack // Load the local variable onto the stack
int index = -1; int index = -1;
int counter = 0; int counter = 0;
for (String key : localVars.keySet()){ for (String key : localVars.keySet()) {
if (key.equals(this.receivers.get(0).identifier)){ if (key.equals(this.receivers.get(i).identifier)) {
index = counter+1; // +1 because the first local variable is at index 1, 0 is used for "this" index = counter + 1; // +1 because the first local variable is at index 1, 0 is used for "this"
break; break;
} }
counter++; counter++;
} }
if (index == -1){ if (index == -1) {
throw new Exception("Variable " + this.receivers.get(0).identifier + " not found"); if (typeContext.get(thisClass).get(this.receivers.get(i).identifier) != null) {
}
mv.visitVarInsn(Opcodes.ALOAD, index); classOfField = typeOfReciever;
typeOfReciever = typeContext.get(typeOfReciever).get(this.receivers.get(i).identifier);
descriptor = getFieldDescriptor(typeContext, typeOfReciever);
// Load the variable onto the stack
mv.visitFieldInsn(Opcodes.GETFIELD, classOfField, receivers.get(i).identifier, descriptor);
continue;
} else { } else {
// Load "this" onto the stack throw new Exception("Variable " + this.receivers.get(i).identifier + " not found");
mv.visitVarInsn(Opcodes.ALOAD, 0);
} }
//Get the field information } else {
String fieldType = typeContext.get(thisClass).get(fieldName); mv.visitVarInsn(Opcodes.ALOAD, index);
// Get the class of the receiver
typeOfReciever = localVars.get(this.receivers.get(i).identifier);
/*
descriptor = getFieldDescriptor(typeContext, typeOfReciever, typeOfReciever);
mv.visitFieldInsn(Opcodes.GETFIELD, thisClass, fieldName, descriptor);
*/
continue;
}
}
// Not the first receiver
else {
// Load the local variable onto the stack
int index = -1;
int counter = 0;
for (String key : localVars.keySet()) {
if (key.equals(this.receivers.get(i).identifier)) {
index = counter + 1; // +1 because the first local variable is at index 1, 0 is used for "this"
break;
}
counter++;
}
if (index == -1) {
if (typeContext.get(typeOfReciever).get(this.receivers.get(i).identifier) != null) {
classOfField = typeOfReciever;
typeOfReciever = typeContext.get(typeOfReciever).get(this.receivers.get(i).identifier);
descriptor = getFieldDescriptor(typeContext, typeOfReciever);
// Load the variable onto the stack
mv.visitFieldInsn(Opcodes.GETFIELD, classOfField, receivers.get(i).identifier, descriptor);
continue;
} else {
throw new Exception("Variable " + this.receivers.get(i).identifier + " not found");
}
} else {
typeOfReciever = localVars.get(this.receivers.get(i).identifier);
descriptor = getFieldDescriptor(typeContext, typeOfReciever);
mv.visitFieldInsn(Opcodes.GETFIELD, typeOfReciever, fieldName, descriptor);
}
}
}
// Load the field in fieldName
// Load the local variable onto the stack
int index = -1;
int counter = 0;
for (String key : localVars.keySet()) {
if (key.equals(fieldName)) {
index = counter + 1; // +1 because the first local variable is at index 1, 0 is used for "this"
break;
}
counter++;
}
if (index == -1) {
if (typeContext.get(typeOfReciever).get(fieldName) != null) {
classOfField = typeOfReciever;
typeOfReciever = typeContext.get(typeOfReciever).get(fieldName);
descriptor = getFieldDescriptor(typeContext, typeOfReciever);
// Load the variable onto the stack
mv.visitFieldInsn(Opcodes.GETFIELD, classOfField, fieldName, descriptor);
} else {
throw new Exception("Variable " + fieldName + " not found");
}
} else {
typeOfReciever = localVars.get(fieldName);
descriptor = getFieldDescriptor(typeContext, typeOfReciever);
mv.visitFieldInsn(Opcodes.GETFIELD, typeOfReciever, fieldName, descriptor);
}
} else if (receivers.get(0).thisExpression) {
// Load the local variable or instVar of this onto the stack
int index = -1;
int counter = 0;
for (String key : localVars.keySet()) {
if (key.equals(fieldName)) {
index = counter + 1; // +1 because the first local variable is at index 1, 0 is used for "this"
break;
}
counter++;
}
if (index == -1) {
mv.visitVarInsn(Opcodes.ALOAD, 0);
} else {
mv.visitVarInsn(Opcodes.ALOAD, index);
}
String fieldType = typeContext.get(thisClass).get(fieldName);
descriptor = getFieldDescriptor(typeContext, fieldType);
//Load the field onto the stack
mv.visitFieldInsn(Opcodes.GETFIELD, thisClass, fieldName, descriptor);
}
}
private String getFieldDescriptor(HashMap<String, HashMap<String, String>> typeContext, String fieldType) {
StringBuilder descriptor = new StringBuilder(); StringBuilder descriptor = new StringBuilder();
@ -105,16 +232,13 @@ public class InstVarExpression extends AbstractType implements IExpression{
descriptor.append("C"); descriptor.append("C");
break; break;
default: default:
String fullReturnType = typeContext.get(thisClass).get(fieldName); String fullReturnType = fieldType;
// If it is a class reference replace the "." with "/" and return it // If it is a class reference replace the "." with "/" and return it
if (fieldType.contains(".")) fullReturnType = fullReturnType.replaceAll("\\.", "/"); if (fieldType.contains(".")) fullReturnType = fullReturnType.replaceAll("\\.", "/");
if (fullReturnType != null) descriptor.append("L").append(fullReturnType).append(";"); if (fullReturnType != null) descriptor.append("L").append(fullReturnType).append(";");
break; break;
} }
return descriptor.toString();
// Load the variable onto the stack
mv.visitFieldInsn(Opcodes.GETFIELD, thisClass, fieldName, descriptor.toString());
} }
@Override @Override

View File

@ -8,6 +8,7 @@ import abstractSyntaxTree.Parameter.Parameter;
import abstractSyntaxTree.Parameter.ParameterList; import abstractSyntaxTree.Parameter.ParameterList;
import abstractSyntaxTree.StatementExpression.AssignStatementExpression; import abstractSyntaxTree.StatementExpression.AssignStatementExpression;
import abstractSyntaxTree.StatementExpression.MethodCallStatementExpression; import abstractSyntaxTree.StatementExpression.MethodCallStatementExpression;
import abstractSyntaxTree.StatementExpression.NewStatementExpression;
import org.objectweb.asm.*; import org.objectweb.asm.*;
import java.util.HashMap; import java.util.HashMap;
@ -66,6 +67,9 @@ public class BlockStatement extends AbstractType implements IStatement {
if (statement instanceof ReturnStatement returnStatement) { if (statement instanceof ReturnStatement returnStatement) {
returnStatement.thisClass = thisClass; returnStatement.thisClass = thisClass;
} }
if (statement instanceof NewStatementExpression newStatementExpression) {
newStatementExpression.thisClass = thisClass;
}
TypeCheckResult typeOfCurrentStatement = statement.typeCheck(methodContext, typeContext, localVars); TypeCheckResult typeOfCurrentStatement = statement.typeCheck(methodContext, typeContext, localVars);
if(statement instanceof MethodCallStatementExpression methodCall){ if(statement instanceof MethodCallStatementExpression methodCall){

View File

@ -9,6 +9,7 @@ import abstractSyntaxTree.Expression.LocalVarIdentifier;
import abstractSyntaxTree.Parameter.ParameterList; import abstractSyntaxTree.Parameter.ParameterList;
import abstractSyntaxTree.StatementExpression.AssignStatementExpression; import abstractSyntaxTree.StatementExpression.AssignStatementExpression;
import abstractSyntaxTree.StatementExpression.MethodCallStatementExpression; import abstractSyntaxTree.StatementExpression.MethodCallStatementExpression;
import abstractSyntaxTree.StatementExpression.NewStatementExpression;
import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes; import org.objectweb.asm.Opcodes;
@ -36,11 +37,14 @@ public class LocalVarDecl extends AbstractType implements IStatement{
if(expression instanceof MethodCallStatementExpression){ if(expression instanceof MethodCallStatementExpression){
MethodCallStatementExpression methodCall = (MethodCallStatementExpression) expression; MethodCallStatementExpression methodCall = (MethodCallStatementExpression) expression;
methodCall.thisClass = this.thisClass; methodCall.thisClass = this.thisClass;
} }
if(expression instanceof LocalVarIdentifier localVarIdentifier){ if(expression instanceof LocalVarIdentifier localVarIdentifier){
localVarIdentifier.thisClass = thisClass; localVarIdentifier.thisClass = thisClass;
} }
if (expression instanceof NewStatementExpression newStatementExpression){
newStatementExpression.thisClass = thisClass;
}
expression.typeCheck(methodContext, typeContext, localVars); expression.typeCheck(methodContext, typeContext, localVars);
} }

View File

@ -139,7 +139,7 @@ public class MethodCallStatementExpression extends AbstractType implements IExpr
} }
// Invoke the current method // Invoke the current method
String descriptor = getMethodDescriptor(receivingMethod.methodName, localVars, methodContext, receivingMethod.arguments, returnOfPreviousMethod); String descriptor = getMethodDescriptor(receivingMethod.methodName, localVars, methodContext, receivingMethod.arguments, returnOfPreviousMethod, owner);
returnOfPreviousMethod = methodContext.get(owner).get(receivingMethod.methodName).keySet().toArray()[0].toString(); returnOfPreviousMethod = methodContext.get(owner).get(receivingMethod.methodName).keySet().toArray()[0].toString();
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, owner, receivingMethod.methodName, descriptor, false); mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, owner, receivingMethod.methodName, descriptor, false);
} }
@ -151,13 +151,18 @@ public class MethodCallStatementExpression extends AbstractType implements IExpr
argument.codeGen(mv, localVars, typeContext, methodContext); argument.codeGen(mv, localVars, typeContext, methodContext);
} }
String descriptor = getMethodDescriptor(methodName, localVars, methodContext, arguments, returnOfPreviousMethod); if (returnOfPreviousMethod != null) {
owner = returnOfPreviousMethod;
}
String descriptor = getMethodDescriptor(methodName, localVars, methodContext, arguments, returnOfPreviousMethod, owner);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, owner, methodName, descriptor, false); mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, owner, methodName, descriptor, false);
} }
// ()I // ()I
private String getMethodDescriptor(String methodName, LinkedHashMap<String, String> localVars, HashMap<String, HashMap<String, HashMap<String, ParameterList>>> methodContext, List<IExpression> arguments, String returnOfPreviousMethod) { private String getMethodDescriptor(String methodName, LinkedHashMap<String, String> localVars, HashMap<String, HashMap<String, HashMap<String, ParameterList>>> methodContext, List<IExpression> arguments, String returnOfPreviousMethod, String owner) {
StringBuilder descriptor = new StringBuilder("("); StringBuilder descriptor = new StringBuilder("(");
for (IExpression argument : arguments) { for (IExpression argument : arguments) {
@ -189,6 +194,7 @@ public class MethodCallStatementExpression extends AbstractType implements IExpr
String classToSearchMethodIn; String classToSearchMethodIn;
//Return Type //Return Type
if (receiver != null) { if (receiver != null) {
if (receiver.identifier != null) {
classToSearchMethodIn = localVars.get(receiver.identifier); classToSearchMethodIn = localVars.get(receiver.identifier);
if (classToSearchMethodIn == null) { if (classToSearchMethodIn == null) {
classToSearchMethodIn = returnOfPreviousMethod; classToSearchMethodIn = returnOfPreviousMethod;
@ -196,6 +202,13 @@ public class MethodCallStatementExpression extends AbstractType implements IExpr
if (classToSearchMethodIn == null) { if (classToSearchMethodIn == null) {
classToSearchMethodIn = thisClass; classToSearchMethodIn = thisClass;
} }
} else {
if (receiver.instVarExpression != null && returnOfPreviousMethod != null) {
classToSearchMethodIn = returnOfPreviousMethod;
} else {
classToSearchMethodIn = owner;
}
}
} else { } else {
classToSearchMethodIn = thisClass; classToSearchMethodIn = thisClass;
} }

View File

@ -5,6 +5,7 @@ import TypeCheck.TypeCheckException;
import TypeCheck.TypeCheckHelper; import TypeCheck.TypeCheckHelper;
import TypeCheck.TypeCheckResult; import TypeCheck.TypeCheckResult;
import abstractSyntaxTree.Expression.IExpression; import abstractSyntaxTree.Expression.IExpression;
import abstractSyntaxTree.Expression.InstVarExpression;
import abstractSyntaxTree.Parameter.Parameter; import abstractSyntaxTree.Parameter.Parameter;
import abstractSyntaxTree.Parameter.ParameterList; import abstractSyntaxTree.Parameter.ParameterList;
import abstractSyntaxTree.Statement.IStatement; import abstractSyntaxTree.Statement.IStatement;
@ -18,6 +19,7 @@ import java.util.List;
public class NewStatementExpression extends AbstractType implements IExpression, IStatement { public class NewStatementExpression extends AbstractType implements IExpression, IStatement {
public String thisClass;
private String className; private String className;
private List<IExpression> arguments; //These need to have a TypeCheckResult private List<IExpression> arguments; //These need to have a TypeCheckResult
@ -31,6 +33,13 @@ public class NewStatementExpression extends AbstractType implements IExpression,
if(!TypeCheckHelper.typeExists(className, new ArrayList<>(typeContext.keySet()))){ if(!TypeCheckHelper.typeExists(className, new ArrayList<>(typeContext.keySet()))){
throw new TypeCheckException("An instance of " + className + " is created, but the type does not exist."); throw new TypeCheckException("An instance of " + className + " is created, but the type does not exist.");
} }
for (IExpression argument : arguments) {
if (argument instanceof InstVarExpression instVarExpression) {
instVarExpression.thisClass = this.thisClass;
}
argument.typeCheck(methodContext, typeContext, localVars);
}
TypeCheckResult result = new TypeCheckResult(); TypeCheckResult result = new TypeCheckResult();
result.type = className; result.type = className;