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:
parent
1dd405a00f
commit
82384886c6
@ -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
|
||||||
|
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(thisClass).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 {
|
||||||
|
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
|
// 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(fieldName)) {
|
||||||
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(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++;
|
||||||
}
|
}
|
||||||
mv.visitVarInsn(Opcodes.ALOAD, index);
|
|
||||||
|
|
||||||
} else {
|
if (index == -1) {
|
||||||
// Load "this" onto the stack
|
mv.visitVarInsn(Opcodes.ALOAD, 0);
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//Get the field information
|
private String getFieldDescriptor(HashMap<String, HashMap<String, String>> typeContext, String fieldType) {
|
||||||
String fieldType = typeContext.get(thisClass).get(fieldName);
|
|
||||||
|
|
||||||
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
|
||||||
|
@ -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){
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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,12 +194,20 @@ public class MethodCallStatementExpression extends AbstractType implements IExpr
|
|||||||
String classToSearchMethodIn;
|
String classToSearchMethodIn;
|
||||||
//Return Type
|
//Return Type
|
||||||
if (receiver != null) {
|
if (receiver != null) {
|
||||||
classToSearchMethodIn = localVars.get(receiver.identifier);
|
if (receiver.identifier != null) {
|
||||||
if (classToSearchMethodIn == null) {
|
classToSearchMethodIn = localVars.get(receiver.identifier);
|
||||||
classToSearchMethodIn = returnOfPreviousMethod;
|
if (classToSearchMethodIn == null) {
|
||||||
}
|
classToSearchMethodIn = returnOfPreviousMethod;
|
||||||
if (classToSearchMethodIn == null) {
|
}
|
||||||
classToSearchMethodIn = thisClass;
|
if (classToSearchMethodIn == null) {
|
||||||
|
classToSearchMethodIn = thisClass;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (receiver.instVarExpression != null && returnOfPreviousMethod != null) {
|
||||||
|
classToSearchMethodIn = returnOfPreviousMethod;
|
||||||
|
} else {
|
||||||
|
classToSearchMethodIn = owner;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
classToSearchMethodIn = thisClass;
|
classToSearchMethodIn = thisClass;
|
||||||
|
@ -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;
|
||||||
|
Loading…
Reference in New Issue
Block a user