From 63059994ec7a8a0c938ffeb3178e159f90d60ea6 Mon Sep 17 00:00:00 2001 From: Jochen Seyfried Date: Fri, 31 May 2024 13:53:06 +0200 Subject: [PATCH] Implemented NewStatementExpression and finished the return of objects (classes, methods) with fully qualified name --- .../abstractSyntaxTree/Class/MethodDecl.java | 3 -- .../Expression/InstVarExpression.java | 23 +++++----- .../AssignStatementExpression.java | 35 ++++++++++----- .../NewStatementExpression.java | 45 ++++++++++++++++++- 4 files changed, 81 insertions(+), 25 deletions(-) diff --git a/src/main/java/abstractSyntaxTree/Class/MethodDecl.java b/src/main/java/abstractSyntaxTree/Class/MethodDecl.java index 6b95799..3efdd30 100644 --- a/src/main/java/abstractSyntaxTree/Class/MethodDecl.java +++ b/src/main/java/abstractSyntaxTree/Class/MethodDecl.java @@ -22,7 +22,6 @@ public class MethodDecl implements Node { public String returnType; public BlockStatement codeBlock; - //TODO: Can this be a linked hash map? --> need it to be to get the index of local variables public LinkedHashMap localVars; public MethodDecl(String classThatContainsMethod, String returnType, String name, ParameterList parameters, BlockStatement codeBlock){ @@ -43,7 +42,6 @@ public class MethodDecl implements Node { return result; } - //Need to get the returnType of the method if it is an object // methodContext (class, (returnType, (identifier, parameter))) public void codeGen(ClassWriter cw, HashMap>> methodContext, HashMap> typeContext) throws Exception { @@ -129,7 +127,6 @@ public class MethodDecl implements Node { } descriptor.append(")"); - // Get the return type // If the return type is null, it is a constructor, and we need to append V if (returnType == null) { diff --git a/src/main/java/abstractSyntaxTree/Expression/InstVarExpression.java b/src/main/java/abstractSyntaxTree/Expression/InstVarExpression.java index 11e42dc..2e65e76 100644 --- a/src/main/java/abstractSyntaxTree/Expression/InstVarExpression.java +++ b/src/main/java/abstractSyntaxTree/Expression/InstVarExpression.java @@ -3,17 +3,17 @@ package abstractSyntaxTree.Expression; import TypeCheck.TypeCheckResult; import abstractSyntaxTree.Class.RefType; import abstractSyntaxTree.Parameter.ParameterList; +import gen.DecafParser; import jdk.jshell.spi.ExecutionControl; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; import java.util.HashMap; import java.util.LinkedHashMap; +import java.util.Objects; public class InstVarExpression implements IExpression{ - //TODO: We have to decide upon more parameters and where they come from, for - // example here we need the index of the field, the class reference and the field name public RefType classRef; public String fieldName; @@ -22,7 +22,6 @@ public class InstVarExpression implements IExpression{ this.fieldName = fieldName; } - @Override public TypeCheckResult typeCheck(HashMap>> methodContext, HashMap> typeContext, HashMap localVars) throws Exception { @@ -42,26 +41,30 @@ public class InstVarExpression implements IExpression{ //Get the field information String fieldType = typeContext.get(classRef.name).get(fieldName); - String fieldDescriptor; + StringBuilder descriptor = new StringBuilder(); + switch (fieldType) { case "int": - fieldDescriptor = "I"; + descriptor.append("I"); break; case "boolean": - fieldDescriptor = "Z"; + descriptor.append("Z"); break; case "char": - fieldDescriptor = "C"; + descriptor.append("C"); break; default: - //TODO: We need the fully qualified name of the class here in field type - fieldDescriptor = "L" + fieldType + ";"; + String fullReturnType = typeContext.get(classRef.name).get(fieldName); + + // If it is a class reference replace the "." with "/" and return it + if (fieldType.contains(".")) fullReturnType = fullReturnType.replaceAll("\\.", "/"); + if (fullReturnType != null) descriptor.append("L").append(fullReturnType).append(";"); break; } // Load the variable onto the stack - mv.visitFieldInsn(Opcodes.GETFIELD, classRef.name, fieldName, fieldDescriptor); + mv.visitFieldInsn(Opcodes.GETFIELD, classRef.name, fieldName, descriptor.toString()); } @Override diff --git a/src/main/java/abstractSyntaxTree/StatementExpression/AssignStatementExpression.java b/src/main/java/abstractSyntaxTree/StatementExpression/AssignStatementExpression.java index df815fd..27d3e37 100644 --- a/src/main/java/abstractSyntaxTree/StatementExpression/AssignStatementExpression.java +++ b/src/main/java/abstractSyntaxTree/StatementExpression/AssignStatementExpression.java @@ -99,20 +99,35 @@ public class AssignStatementExpression extends AbstractType implements IExpressi // Load "this" onto the stack mv.visitVarInsn(Opcodes.ALOAD, 0); - } - /* - if (left instanceof VarRefExpression varRef) { - //TODO: Implement the handling of a variable reference --> I need a list of local variables - // for that to determine if the variable is a local or field variable - } else if (left instanceof InstVarExpression instVar) { + + // Duplicate the top of the stack as we'll need it for both the PUTFIELD and subsequent expressions mv.visitInsn(Opcodes.DUP_X1); - // We now again need the owner (class reference), name (of the Field in the owner) and type of the field - //mv.visitFieldInsn(Opcodes.PUTFIELD, instVar.className, instVar.varName, instVar.type); + // Get the field information + String fieldType = typeContext.get(instVar.classRef.name).get(instVar.fieldName); + + StringBuilder descriptor = new StringBuilder(); + + switch (fieldType) { + case "int": + descriptor.append("I"); + break; + case "bool": + descriptor.append("Z"); + break; + default: + String fullReturnType = typeContext.get(instVar.classRef.name).get(instVar.fieldName); + + // If it is a class reference replace the "." with "/" and return it + if (fieldType.contains(".")) fullReturnType = fullReturnType.replaceAll("\\.", "/"); + if (fullReturnType != null) descriptor.append("L").append(fullReturnType).append(";"); + break; + } + + // Store the value in the field + mv.visitFieldInsn(Opcodes.PUTFIELD, instVar.classRef.name, instVar.fieldName, descriptor.toString()); } } - */ - } @Override public boolean equals(Object o) { diff --git a/src/main/java/abstractSyntaxTree/StatementExpression/NewStatementExpression.java b/src/main/java/abstractSyntaxTree/StatementExpression/NewStatementExpression.java index 1b7ab7e..61a22be 100644 --- a/src/main/java/abstractSyntaxTree/StatementExpression/NewStatementExpression.java +++ b/src/main/java/abstractSyntaxTree/StatementExpression/NewStatementExpression.java @@ -4,6 +4,7 @@ import TypeCheck.AbstractType; import TypeCheck.TypeCheckHelper; import TypeCheck.TypeCheckResult; import abstractSyntaxTree.Expression.IExpression; +import abstractSyntaxTree.Parameter.Parameter; import abstractSyntaxTree.Parameter.ParameterList; import abstractSyntaxTree.Statement.IStatement; import org.objectweb.asm.MethodVisitor; @@ -17,9 +18,11 @@ import java.util.List; public class NewStatementExpression extends AbstractType implements IExpression, IStatement { private String className; + private List arguments; - public NewStatementExpression(String className) { + public NewStatementExpression(String className, List arguments) { this.className = className; + this.arguments = arguments; } @Override @@ -40,7 +43,45 @@ public class NewStatementExpression extends AbstractType implements IExpression, //Duplicate the reference, so I can use it after the INVOKE consumes one mv.visitInsn(Opcodes.DUP); + + for (IExpression argument : arguments) { + argument.codeGen(mv, localVars, typeContext); + } + String descriptor = getConstructorDescriptor(); + //Call the constructor - mv.visitMethodInsn(Opcodes.INVOKESPECIAL, className, "", "()V", false); + mv.visitMethodInsn(Opcodes.INVOKESPECIAL, className, "", descriptor, false); + } + + private String getConstructorDescriptor() { + StringBuilder descriptor = new StringBuilder(); + + for (IExpression parameter : arguments) { + TypeCheckResult result = parameter.getTypeCheckResult(); + String type = result.type; + + switch (type) { + case "int": + descriptor.append("I"); + break; + case "bool": + 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(")V"); // Constructors always return void + return descriptor.toString(); } }