From 377e9b3193ccd1f2a1c50ce43f9cecc885b6c550 Mon Sep 17 00:00:00 2001 From: Jochen Seyfried Date: Thu, 27 Jun 2024 09:27:08 +0200 Subject: [PATCH] Implemented the new codeGen for MethodCallStatementExpression --- src/main/java/Compiler.java | 2 +- .../Expression/UnaryExpression.java | 4 +- .../MethodCallStatementExpression.java | 85 +++++++++++++++++++ 3 files changed, 88 insertions(+), 3 deletions(-) diff --git a/src/main/java/Compiler.java b/src/main/java/Compiler.java index ea7b0d6..fb2f6d9 100644 --- a/src/main/java/Compiler.java +++ b/src/main/java/Compiler.java @@ -18,7 +18,7 @@ public class Compiler { public static void main(String[] args) throws Exception{ - Path filePath = Paths.get("src/main/java/TestInput.java"); + Path filePath = Paths.get("src/main/java/Input.java"); // todo remove this debug info diff --git a/src/main/java/abstractSyntaxTree/Expression/UnaryExpression.java b/src/main/java/abstractSyntaxTree/Expression/UnaryExpression.java index fdfcdcd..5577cc7 100644 --- a/src/main/java/abstractSyntaxTree/Expression/UnaryExpression.java +++ b/src/main/java/abstractSyntaxTree/Expression/UnaryExpression.java @@ -24,7 +24,7 @@ public class UnaryExpression extends AbstractType implements IExpression{ public TypeCheckResult typeCheck(HashMap>> methodContext, HashMap> typeContext, HashMap localVars) throws TypeCheckException { TypeCheckResult result = new TypeCheckResult(); - TypeCheckResult operandTypeCheckResult = operand.typeCheck(); + TypeCheckResult operandTypeCheckResult = operand.typeCheck(methodContext, typeContext, localVars); String operandType = operandTypeCheckResult.type; switch (operator) { @@ -53,7 +53,7 @@ public class UnaryExpression extends AbstractType implements IExpression{ @Override public void codeGen(MethodVisitor mv, LinkedHashMap localVars, HashMap> typeContext, HashMap>> methodContext) throws Exception { - operand.codeGen(mv); + operand.codeGen(mv, localVars, typeContext, methodContext); switch (operator) { case "!": diff --git a/src/main/java/abstractSyntaxTree/StatementExpression/MethodCallStatementExpression.java b/src/main/java/abstractSyntaxTree/StatementExpression/MethodCallStatementExpression.java index 63260de..d4e45f4 100644 --- a/src/main/java/abstractSyntaxTree/StatementExpression/MethodCallStatementExpression.java +++ b/src/main/java/abstractSyntaxTree/StatementExpression/MethodCallStatementExpression.java @@ -82,9 +82,94 @@ public class MethodCallStatementExpression extends AbstractType implements IExpr //Errors occur due to the change in parameter in the RefType class @Override public void codeGen(MethodVisitor mv, LinkedHashMap localVars, HashMap> typeContext, HashMap>> methodContext) throws Exception { + String owner; + + // Load the object onto the stack + if (receiver != null) { + if (receiver.thisExpression) { + mv.visitVarInsn(Opcodes.ALOAD, 0); + owner = thisClass; + } else if (receiver.instVarExpression != null) { + receiver.instVarExpression.codeGen(mv, localVars, typeContext, methodContext); + owner = receiver.instVarExpression.getTypeCheckResult().type; + } else if (receiver.newStatementExpression != null) { + receiver.newStatementExpression.codeGen(mv, localVars, typeContext, methodContext); + owner = receiver.newStatementExpression.getTypeCheckResult().type; + } else if (receiver.identifier != null) { + String type = localVars.get(receiver.identifier); + if (type == null) { + // If it is not a local variable, assume it is a field of the current class + type = typeContext.get(thisClass).get(receiver.identifier); + mv.visitVarInsn(Opcodes.ALOAD, 0); // Load "this" onto the stack + mv.visitFieldInsn(Opcodes.GETFIELD, thisClass, receiver.identifier, "L" + type + ";"); // Load the field onto the stack + } else { + // It's a local variable + int index = localVars.keySet().stream().toList().indexOf(receiver.identifier); + int opcode = type.equals("int") ? Opcodes.ILOAD : Opcodes.ALOAD; + mv.visitVarInsn(opcode, index); // Load local variable onto the stack + } + owner = type; + } else { + throw new ExecutionControl.NotImplementedException("Receiver type not supported."); + } + } else { + throw new ExecutionControl.NotImplementedException("Receiver is null."); + } + /* + else { + + String type = localVars.get(receiver.identifier); + if (type == null) { + type = typeContext.get(thisClass).get(receiver.identifier); + } + mv.visitVarInsn(Opcodes.ALOAD, 1); + mv.visitFieldInsn(Opcodes.GETFIELD, thisClass, receiver.identifier, "L" + type + ";"); + } + */ + + // Generate the code for each argument expression + for (IExpression argument : arguments) { + argument.codeGen(mv, localVars, typeContext, methodContext); + } + + // Invoke the method + String descriptor = getMethodDescriptor(); + mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, owner, methodName, descriptor, false); } + private String getMethodDescriptor() { + StringBuilder descriptor = new StringBuilder("("); + + for (IExpression argument : arguments) { + TypeCheckResult result = argument.getTypeCheckResult(); + String type = result.type; + + switch (type) { + case "int": + descriptor.append("I"); + break; + case "boolean": + descriptor.append("Z"); + break; + case "char": + descriptor.append("C"); + break; + case "void": + descriptor.append("V"); + break; + default: + // If it is a class reference replace the "." with "/" and return it + if (type.contains(".")) type = type.replaceAll("\\.", "/"); + descriptor.append("L").append(type).append(";"); + break; + } + } + descriptor.append(")"); // Methods always return void + return descriptor.toString(); + } + + @Override public boolean equals(Object o) { if (this == o) return true;