diff --git a/src/main/java/abstractSyntaxTree/Class/FieldDecl.java b/src/main/java/abstractSyntaxTree/Class/FieldDecl.java index 11a731d..0e2e0c1 100644 --- a/src/main/java/abstractSyntaxTree/Class/FieldDecl.java +++ b/src/main/java/abstractSyntaxTree/Class/FieldDecl.java @@ -6,6 +6,8 @@ import TypeCheck.TypeCheckResult; import abstractSyntaxTree.Node; import abstractSyntaxTree.Program; import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.FieldVisitor; +import org.objectweb.asm.Opcodes; import java.util.ArrayList; import java.util.HashMap; @@ -39,6 +41,22 @@ public class FieldDecl extends AbstractType implements IClass, Node { @Override public void codeGen(ClassWriter cw) { + //TODO: Do we have fields with initial values? + FieldVisitor fv = cw.visitField(Opcodes.ACC_PUBLIC, identifier, getFieldDescriptor(), null, null); + fv.visitEnd(); + } + private String getFieldDescriptor() { + //TODO: Maybe we have to check for arrays? + switch (type) { + case "int": + return "I"; + case "boolean": + return "Z"; + case "char": + return "C"; + default: + return "L" + type + ";"; + } } } diff --git a/src/main/java/abstractSyntaxTree/Class/MethodDecl.java b/src/main/java/abstractSyntaxTree/Class/MethodDecl.java index c2fbecd..a1fc503 100644 --- a/src/main/java/abstractSyntaxTree/Class/MethodDecl.java +++ b/src/main/java/abstractSyntaxTree/Class/MethodDecl.java @@ -2,25 +2,30 @@ package abstractSyntaxTree.Class; import TypeCheck.TypeCheckResult; import abstractSyntaxTree.Node; +import abstractSyntaxTree.Parameter.Parameter; import abstractSyntaxTree.Parameter.ParameterList; import abstractSyntaxTree.Program; import abstractSyntaxTree.Statement.BlockStatement; import abstractSyntaxTree.Statement.IStatement; -import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.*; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Stack; public class MethodDecl implements IClass, Node { + //Class Name public String classThatContainsMethod; + + //Method Name public String name; public ParameterList parameters; public String returnType; public BlockStatement codeBlock; - public Map localVars; + public HashMap localVars; public MethodDecl(String classThatContainsMethod, String returnType, String name, ParameterList parameters, BlockStatement codeBlock){ this.classThatContainsMethod = classThatContainsMethod; @@ -28,6 +33,7 @@ public class MethodDecl implements IClass, Node { this.name = name; this.parameters = parameters; this.codeBlock = codeBlock; + this.localVars = new HashMap<>(); } public TypeCheckResult typeCheck(HashMap>>> methodContext, HashMap> typeContext) throws Exception { @@ -40,5 +46,92 @@ public class MethodDecl implements IClass, Node { @Override public void codeGen(ClassWriter cw) throws Exception { + localVars.put("this", classThatContainsMethod); + for (Parameter param : parameters.parameterList) { + localVars.put(param.identifier, param.type); + } + + // check if the method is a constructor + if (classThatContainsMethod.equals(name) && returnType == null) { + MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "", getMethodDescriptor(), null, null); + + //Call the superclass constructor + mv.visitVarInsn(Opcodes.ALOAD, 0); + mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", "", "()V", false); + + mv.visitCode(); + codeBlock.codeGen(mv, localVars); //TODO: pass the local vars? --> codeGen for block not yet implemented + mv.visitInsn(Opcodes.RETURN); + + //automatically computed max stack and max locals + mv.visitMaxs(0, 0); + mv.visitEnd(); + } else if (name.equals("main")) { //TODO: Check how we distinguish the main method + int access = Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC; + + MethodVisitor mv = cw.visitMethod(access, name, "([Ljava/lang/String;)V", null, null); + + mv.visitCode(); + codeBlock.codeGen(mv, localVars); //TODO: pass the local vars? --> codeGen for block not yet implemented + mv.visitInsn(Opcodes.RETURN); + + mv.visitMaxs(0, 0); + mv.visitEnd(); + + } else { + MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC, name, getMethodDescriptor(), null, null); + + mv.visitCode(); + codeBlock.codeGen(mv, localVars); //TODO: pass the local vars? --> codeGen for block not yet implemented + + // We have to check the return type to get the return opcode + // For methods which return an actual value, the return opcode is created in the method body to ensure the + // correct return value is on the stack + if (returnType.equals("void")) mv.visitInsn(Opcodes.RETURN); + + mv.visitMaxs(0, 0); + mv.visitEnd(); + } + } + + private String getMethodDescriptor() { + // get the method descriptor + StringBuilder descriptor = new StringBuilder("("); + + // Iterate over the parameters and add them to the descriptor + for (Parameter param : parameters.parameterList) { + switch (param.type) { + case "int" -> descriptor.append("I"); + case "boolean" -> descriptor.append("Z"); + case "char" -> descriptor.append("C"); + case "void" -> descriptor.append("V"); + default -> + // object + //TODO: This is not finished + descriptor.append("L").append(param.type).append(";"); + } + } + 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) { + descriptor.append("V"); + } else { + switch (returnType) { + case "int" -> descriptor.append("I"); + case "boolean" -> descriptor.append("Z"); + case "char" -> descriptor.append("C"); + case "void" -> descriptor.append("V"); + + //TODO: This is not finished --> we need to append the fully qualified name of the object + // Need to make sure what we get + default -> + // object + descriptor.append("L").append(returnType).append(";"); + } + } + return descriptor.toString(); } } diff --git a/src/main/java/abstractSyntaxTree/Class/RefType.java b/src/main/java/abstractSyntaxTree/Class/RefType.java index 7cd2519..eb5a687 100644 --- a/src/main/java/abstractSyntaxTree/Class/RefType.java +++ b/src/main/java/abstractSyntaxTree/Class/RefType.java @@ -12,10 +12,10 @@ import java.util.List; public class RefType extends AbstractType implements IClass, Node { + //Class Name public String name; public List fieldDecls; public List methodDecls; - private boolean hasMain; public RefType(String name, List fieldDecls, diff --git a/src/main/java/abstractSyntaxTree/Statement/BlockStatement.java b/src/main/java/abstractSyntaxTree/Statement/BlockStatement.java index cac259d..a57b370 100644 --- a/src/main/java/abstractSyntaxTree/Statement/BlockStatement.java +++ b/src/main/java/abstractSyntaxTree/Statement/BlockStatement.java @@ -46,9 +46,15 @@ public class BlockStatement extends AbstractType implements IStatement{ } @Override - public void codeGen(MethodVisitor mv) throws Exception { + public void codeGen(MethodVisitor mv, HashMap localVars) throws Exception { + // Create a new HashMap for the local variables of the block + // It has every variable of the parent block + // This Map is discarded at the end of the block + //TODO: Do this for every block --> if, while, ... + HashMap blockLocalVars = new HashMap<>(localVars); + for (IStatement statement : statements) { - statement.codeGen(mv); //TODO: I think we need to pass the symbol table here + statement.codeGen(mv, blockLocalVars); } } } diff --git a/src/main/java/abstractSyntaxTree/Statement/EmptyStatement.java b/src/main/java/abstractSyntaxTree/Statement/EmptyStatement.java index 5065e7a..70a82b5 100644 --- a/src/main/java/abstractSyntaxTree/Statement/EmptyStatement.java +++ b/src/main/java/abstractSyntaxTree/Statement/EmptyStatement.java @@ -21,7 +21,7 @@ public class EmptyStatement extends AbstractType implements IStatement{ } @Override - public void codeGen(MethodVisitor mv) throws Exception { + public void codeGen(MethodVisitor mv, HashMap localVars) throws Exception { //An empty statement does not generate any code } } diff --git a/src/main/java/abstractSyntaxTree/Statement/IStatement.java b/src/main/java/abstractSyntaxTree/Statement/IStatement.java index bcc5162..5788250 100644 --- a/src/main/java/abstractSyntaxTree/Statement/IStatement.java +++ b/src/main/java/abstractSyntaxTree/Statement/IStatement.java @@ -14,5 +14,5 @@ public interface IStatement { TypeCheckResult typeCheck(HashMap>>> methodContext, HashMap> typeContext) throws Exception; - void codeGen(MethodVisitor mv) throws Exception; + void codeGen(MethodVisitor mv, HashMap localVars) throws Exception; } diff --git a/src/main/java/abstractSyntaxTree/Statement/IfElseStatement.java b/src/main/java/abstractSyntaxTree/Statement/IfElseStatement.java index 1afc7bb..7ad152c 100644 --- a/src/main/java/abstractSyntaxTree/Statement/IfElseStatement.java +++ b/src/main/java/abstractSyntaxTree/Statement/IfElseStatement.java @@ -46,7 +46,7 @@ public class IfElseStatement extends AbstractType implements IStatement{ } @Override - public void codeGen(MethodVisitor mv) throws Exception { + public void codeGen(MethodVisitor mv, HashMap localVars) throws Exception { Label conditionFalse = new Label(); Label statementEnd = new Label(); diff --git a/src/main/java/abstractSyntaxTree/Statement/IfStatement.java b/src/main/java/abstractSyntaxTree/Statement/IfStatement.java index 29ca025..0e63d40 100644 --- a/src/main/java/abstractSyntaxTree/Statement/IfStatement.java +++ b/src/main/java/abstractSyntaxTree/Statement/IfStatement.java @@ -39,7 +39,7 @@ public class IfStatement extends AbstractType implements IStatement{ } @Override - public void codeGen(MethodVisitor mv) throws Exception { + public void codeGen(MethodVisitor mv, HashMap localVars) throws Exception { Label conditionFalse = new Label(); diff --git a/src/main/java/abstractSyntaxTree/Statement/ReturnStatement.java b/src/main/java/abstractSyntaxTree/Statement/ReturnStatement.java index f409ea2..683813d 100644 --- a/src/main/java/abstractSyntaxTree/Statement/ReturnStatement.java +++ b/src/main/java/abstractSyntaxTree/Statement/ReturnStatement.java @@ -39,7 +39,7 @@ public class ReturnStatement extends AbstractType implements IStatement{ // This is a problem at "BinaryExpression" and here because we need to know the type to return // At this point in time we can either return reference types or have an error message @Override - public void codeGen(MethodVisitor mv) throws Exception { + public void codeGen(MethodVisitor mv, HashMap localVars) throws Exception { if (expression != null) { expression.codeGen(mv); diff --git a/src/main/java/abstractSyntaxTree/Statement/WhileStatement.java b/src/main/java/abstractSyntaxTree/Statement/WhileStatement.java index d325e0a..2e67c3b 100644 --- a/src/main/java/abstractSyntaxTree/Statement/WhileStatement.java +++ b/src/main/java/abstractSyntaxTree/Statement/WhileStatement.java @@ -39,7 +39,7 @@ public class WhileStatement extends AbstractType implements IStatement { } @Override - public void codeGen(MethodVisitor mv) throws Exception { + public void codeGen(MethodVisitor mv, HashMap localVars) throws Exception { Label conditionFalse = new Label(); Label LoopStart = new Label();