From 07552e704ee227a3204ba9243985b875f4971a2d Mon Sep 17 00:00:00 2001 From: Jochen Seyfried Date: Sun, 30 Jun 2024 18:04:04 +0200 Subject: [PATCH] Added bytecodeGeneration for PrintStatement and fixed basic MethodCall --- .../abstractSyntaxTree/Class/MethodDecl.java | 3 +- .../Statement/PrintStatement.java | 23 +++++++++++ .../MethodCallStatementExpression.java | 39 ++++++++++++++++--- 3 files changed, 59 insertions(+), 6 deletions(-) diff --git a/src/main/java/abstractSyntaxTree/Class/MethodDecl.java b/src/main/java/abstractSyntaxTree/Class/MethodDecl.java index d836d61..e87d570 100644 --- a/src/main/java/abstractSyntaxTree/Class/MethodDecl.java +++ b/src/main/java/abstractSyntaxTree/Class/MethodDecl.java @@ -54,7 +54,7 @@ public class MethodDecl implements Node { } //Need to get the returnType of the method if it is an object - // methodContext (class, (returnType, (identifier, parameter))) + // methodContext (class, (identifier, (returnType, parameter))) // typeContext (class, (type, identifier)) public void codeGen(ClassWriter cw, HashMap>> methodContext, HashMap> typeContext, List fieldDecls) throws Exception { @@ -75,6 +75,7 @@ public class MethodDecl implements Node { HashMap classFields = typeContext.get(classThatContainsMethod); + //Set the fields of the class for (Map.Entry entry : classFields.entrySet()) { String fieldName = entry.getKey(); for (FieldDecl field : fieldDecls) { diff --git a/src/main/java/abstractSyntaxTree/Statement/PrintStatement.java b/src/main/java/abstractSyntaxTree/Statement/PrintStatement.java index 8b5a870..35b2985 100644 --- a/src/main/java/abstractSyntaxTree/Statement/PrintStatement.java +++ b/src/main/java/abstractSyntaxTree/Statement/PrintStatement.java @@ -5,6 +5,7 @@ import TypeCheck.TypeCheckException; import TypeCheck.TypeCheckResult; import abstractSyntaxTree.Parameter.ParameterList; import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; import java.util.HashMap; import java.util.LinkedHashMap; @@ -34,6 +35,28 @@ public class PrintStatement extends AbstractType implements IStatement { @Override public void codeGen(MethodVisitor mv, LinkedHashMap localVars, HashMap> typeContext, HashMap>> methodContext) throws Exception { + // Load System.out onto the stack + mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"); + // Load the value of the variable onto the stack + int index = -1; + int counter = 0; + for (String key : localVars.keySet()){ + if (key.equals(variableName)){ + index = counter+1; // +1 because the first local variable is at index 1, 0 is used for "this" + break; + } + counter++; + } + + if (index == -1){ + throw new Exception("Variable " + variableName + " not found"); + } + + mv.visitVarInsn(Opcodes.ILOAD, index); + + // Call the println method + mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/PrintStream", "println", "(I)V", false); } + } diff --git a/src/main/java/abstractSyntaxTree/StatementExpression/MethodCallStatementExpression.java b/src/main/java/abstractSyntaxTree/StatementExpression/MethodCallStatementExpression.java index d8bd99c..abf5320 100644 --- a/src/main/java/abstractSyntaxTree/StatementExpression/MethodCallStatementExpression.java +++ b/src/main/java/abstractSyntaxTree/StatementExpression/MethodCallStatementExpression.java @@ -105,7 +105,7 @@ public class MethodCallStatementExpression extends AbstractType implements IExpr 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 index = localVars.keySet().stream().toList().indexOf(receiver.identifier)+1; // +1 because the first local variable is at index 1, 0 is used for "this" int opcode = type.equals("int") ? Opcodes.ILOAD : Opcodes.ALOAD; mv.visitVarInsn(opcode, index); // Load local variable onto the stack } @@ -134,12 +134,12 @@ public class MethodCallStatementExpression extends AbstractType implements IExpr } // Invoke the method - String descriptor = getMethodDescriptor(); + String descriptor = getMethodDescriptor(localVars, methodContext); mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, owner, methodName, descriptor, false); } - - private String getMethodDescriptor() { + // ()I + private String getMethodDescriptor(LinkedHashMap localVars, HashMap>> methodContext) { StringBuilder descriptor = new StringBuilder("("); for (IExpression argument : arguments) { @@ -166,7 +166,36 @@ public class MethodCallStatementExpression extends AbstractType implements IExpr break; } } - descriptor.append(")"); // Methods always return void + descriptor.append(")"); + + //Return Type + String classToSearchMethodIn = localVars.get(receiver.identifier); + if (classToSearchMethodIn == null) + classToSearchMethodIn = thisClass; + + String returnType = methodContext.get(classToSearchMethodIn).get(methodName).keySet().toArray()[0].toString(); + + switch (returnType) { + 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 (returnType.contains(".")) returnType = returnType.replaceAll("\\.", "/"); + descriptor.append("L").append(returnType).append(";"); + break; + } + System.out.println("Descriptor: " + descriptor.toString()); + return descriptor.toString(); }