diff --git a/src/main/java/abstractSyntaxTree/Class/MethodDecl.java b/src/main/java/abstractSyntaxTree/Class/MethodDecl.java index 6d31059..c59353f 100644 --- a/src/main/java/abstractSyntaxTree/Class/MethodDecl.java +++ b/src/main/java/abstractSyntaxTree/Class/MethodDecl.java @@ -84,7 +84,7 @@ public class MethodDecl implements Node { mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", "", descriptor, false); mv.visitCode(); - codeBlock.codeGen(mv, localVars, typeContext); + codeBlock.codeGen(mv, localVars, typeContext, methodContext); mv.visitInsn(Opcodes.RETURN); //automatically computed max stack and max locals @@ -96,7 +96,7 @@ public class MethodDecl implements Node { MethodVisitor mv = cw.visitMethod(access, name, "([Ljava/lang/String;)V", null, null); mv.visitCode(); - codeBlock.codeGen(mv, localVars, typeContext); + codeBlock.codeGen(mv, localVars, typeContext, methodContext); mv.visitInsn(Opcodes.RETURN); mv.visitMaxs(0, 0); @@ -106,7 +106,7 @@ public class MethodDecl implements Node { MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC, name, getMethodDescriptor(methodContext), null, null); mv.visitCode(); - codeBlock.codeGen(mv, localVars, typeContext); + codeBlock.codeGen(mv, localVars, typeContext, methodContext); // 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 diff --git a/src/main/java/abstractSyntaxTree/Expression/BinaryExpression.java b/src/main/java/abstractSyntaxTree/Expression/BinaryExpression.java index d2b4713..5086324 100644 --- a/src/main/java/abstractSyntaxTree/Expression/BinaryExpression.java +++ b/src/main/java/abstractSyntaxTree/Expression/BinaryExpression.java @@ -67,7 +67,7 @@ public class BinaryExpression extends AbstractType implements IExpression{ } @Override - public void codeGen(MethodVisitor mv, LinkedHashMap localVars, HashMap> typeContext) throws Exception { + public void codeGen(MethodVisitor mv, LinkedHashMap localVars, HashMap> typeContext, HashMap>> methodContext) throws Exception { // Label for the jump instruction Label operationFalse = new Label(); //Operation is false Label operationTrue = new Label(); //Operation is true @@ -77,88 +77,88 @@ public class BinaryExpression extends AbstractType implements IExpression{ // Bytecode for the binary operation switch (operator) { case "&&": - left.codeGen(mv, localVars, typeContext); + left.codeGen(mv, localVars, typeContext, methodContext); mv.visitJumpInsn(Opcodes.IFEQ, operationFalse); // IFEQ --> "if equals to zero" (false) --> if left exp is false - right.codeGen(mv, localVars, typeContext); + right.codeGen(mv, localVars, typeContext, methodContext); mv.visitJumpInsn(Opcodes.IFEQ, operationFalse); // If right exp is false, jump to the end of the whole expression mv.visitJumpInsn(Opcodes.GOTO, operationTrue); // If it reaches this point, the right exp is true break; case "||": - left.codeGen(mv, localVars, typeContext); + left.codeGen(mv, localVars, typeContext, methodContext); mv.visitJumpInsn(Opcodes.IFNE, operationTrue); // IFNE --> "if not equals to zero" (true) --> if left exp is true - right.codeGen(mv, localVars, typeContext); + right.codeGen(mv, localVars, typeContext, methodContext); mv.visitJumpInsn(Opcodes.IFNE, operationTrue); break; case "==": // Keep in mind that only primitive types are allowed in this case (at this time) - left.codeGen(mv, localVars, typeContext); - right.codeGen(mv, localVars, typeContext); + left.codeGen(mv, localVars, typeContext, methodContext); + right.codeGen(mv, localVars, typeContext, methodContext); mv.visitJumpInsn(Opcodes.IF_ICMPEQ, operationTrue); // If the two values are equal, jump to the end of the expression break; case "<": - left.codeGen(mv, localVars, typeContext); - right.codeGen(mv, localVars, typeContext); + left.codeGen(mv, localVars, typeContext, methodContext); + right.codeGen(mv, localVars, typeContext, methodContext); mv.visitJumpInsn(Opcodes.IF_ICMPLT, operationTrue); // Checks only on less than, not equal break; case ">": - left.codeGen(mv, localVars, typeContext); - right.codeGen(mv, localVars, typeContext); + left.codeGen(mv, localVars, typeContext, methodContext); + right.codeGen(mv, localVars, typeContext, methodContext); mv.visitJumpInsn(Opcodes.IF_ICMPGT, operationTrue); // Checks only on greater than, not equal break; case "<=": - left.codeGen(mv, localVars, typeContext); - right.codeGen(mv, localVars, typeContext); + left.codeGen(mv, localVars, typeContext, methodContext); + right.codeGen(mv, localVars, typeContext, methodContext); mv.visitJumpInsn(Opcodes.IF_ICMPLE, operationTrue); // Checks on less than OR equal break; case ">=": - left.codeGen(mv, localVars, typeContext); - right.codeGen(mv, localVars, typeContext); + left.codeGen(mv, localVars, typeContext, methodContext); + right.codeGen(mv, localVars, typeContext, methodContext); mv.visitJumpInsn(Opcodes.IF_ICMPGE, operationTrue); // Checks on greater than OR equal break; case "!=": - left.codeGen(mv, localVars, typeContext); - right.codeGen(mv, localVars, typeContext); + left.codeGen(mv, localVars, typeContext, methodContext); + right.codeGen(mv, localVars, typeContext, methodContext); mv.visitJumpInsn(Opcodes.IF_ICMPNE, operationTrue); // Checks on not equal break; case "+": - left.codeGen(mv, localVars, typeContext); - right.codeGen(mv, localVars, typeContext); + left.codeGen(mv, localVars, typeContext, methodContext); + right.codeGen(mv, localVars, typeContext, methodContext); mv.visitInsn(Opcodes.IADD); break; case "-": - left.codeGen(mv, localVars, typeContext); - right.codeGen(mv, localVars, typeContext); + left.codeGen(mv, localVars, typeContext, methodContext); + right.codeGen(mv, localVars, typeContext, methodContext); mv.visitInsn(Opcodes.ISUB); break; case "*": - left.codeGen(mv, localVars, typeContext); - right.codeGen(mv, localVars, typeContext); + left.codeGen(mv, localVars, typeContext, methodContext); + right.codeGen(mv, localVars, typeContext, methodContext); mv.visitInsn(Opcodes.IMUL); break; case "/": - left.codeGen(mv, localVars, typeContext); - right.codeGen(mv, localVars, typeContext); + left.codeGen(mv, localVars, typeContext, methodContext); + right.codeGen(mv, localVars, typeContext, methodContext); mv.visitInsn(Opcodes.IDIV); break; diff --git a/src/main/java/abstractSyntaxTree/Expression/BooleanConstantExpression.java b/src/main/java/abstractSyntaxTree/Expression/BooleanConstantExpression.java index da0e925..1400bd2 100644 --- a/src/main/java/abstractSyntaxTree/Expression/BooleanConstantExpression.java +++ b/src/main/java/abstractSyntaxTree/Expression/BooleanConstantExpression.java @@ -26,7 +26,7 @@ public class BooleanConstantExpression extends AbstractType implements IExpressi } @Override - public void codeGen(MethodVisitor mv, LinkedHashMap localVars, HashMap> typeContext) throws Exception { + public void codeGen(MethodVisitor mv, LinkedHashMap localVars, HashMap> typeContext, HashMap>> methodContext) throws Exception { if (value){ mv.visitInsn(Opcodes.ICONST_1); } else { diff --git a/src/main/java/abstractSyntaxTree/Expression/CharConstantExpression.java b/src/main/java/abstractSyntaxTree/Expression/CharConstantExpression.java index 1485cd5..00df59e 100644 --- a/src/main/java/abstractSyntaxTree/Expression/CharConstantExpression.java +++ b/src/main/java/abstractSyntaxTree/Expression/CharConstantExpression.java @@ -25,7 +25,7 @@ public class CharConstantExpression extends AbstractType implements IExpression{ } @Override - public void codeGen(MethodVisitor mv, LinkedHashMap localVars, HashMap> typeContext) throws Exception { + public void codeGen(MethodVisitor mv, LinkedHashMap localVars, HashMap> typeContext, HashMap>> methodContext) throws Exception { mv.visitIntInsn(Opcodes.BIPUSH, (int) value); } diff --git a/src/main/java/abstractSyntaxTree/Expression/IExpression.java b/src/main/java/abstractSyntaxTree/Expression/IExpression.java index 958a6de..0d51b32 100644 --- a/src/main/java/abstractSyntaxTree/Expression/IExpression.java +++ b/src/main/java/abstractSyntaxTree/Expression/IExpression.java @@ -15,7 +15,7 @@ public interface IExpression extends Node { TypeCheckResult typeCheck(HashMap>> methodContext, HashMap> typeContext, HashMap localVars) throws TypeCheckException; // visit method for code generation - void codeGen(MethodVisitor mv, LinkedHashMap localVars, HashMap> typeContext) throws Exception; + void codeGen(MethodVisitor mv, LinkedHashMap localVars, HashMap> typeContext, HashMap>> methodContext) throws Exception; TypeCheckResult getTypeCheckResult(); } diff --git a/src/main/java/abstractSyntaxTree/Expression/InstVarExpression.java b/src/main/java/abstractSyntaxTree/Expression/InstVarExpression.java index eefab82..ee15a8c 100644 --- a/src/main/java/abstractSyntaxTree/Expression/InstVarExpression.java +++ b/src/main/java/abstractSyntaxTree/Expression/InstVarExpression.java @@ -42,7 +42,7 @@ public class InstVarExpression extends AbstractType implements IExpression{ @Override // typeContext: (ClassName, (FieldName, FieldType)) - public void codeGen(MethodVisitor mv, LinkedHashMap localVars, HashMap> typeContext) throws Exception { + public void codeGen(MethodVisitor mv, LinkedHashMap localVars, HashMap> typeContext, HashMap>> methodContext) throws Exception { // Load "this" onto the stack mv.visitVarInsn(Opcodes.ALOAD, 0); diff --git a/src/main/java/abstractSyntaxTree/Expression/IntConstantExpression.java b/src/main/java/abstractSyntaxTree/Expression/IntConstantExpression.java index fd1fb24..e3a689b 100644 --- a/src/main/java/abstractSyntaxTree/Expression/IntConstantExpression.java +++ b/src/main/java/abstractSyntaxTree/Expression/IntConstantExpression.java @@ -27,7 +27,7 @@ public class IntConstantExpression extends AbstractType implements IExpression{ } @Override - public void codeGen(MethodVisitor mv, LinkedHashMap localVars, HashMap> typeContext) throws Exception { + public void codeGen(MethodVisitor mv, LinkedHashMap localVars, HashMap> typeContext, HashMap>> methodContext) throws Exception { //TODO: When we are finished this can be done more efficiently mv.visitLdcInsn(value); } diff --git a/src/main/java/abstractSyntaxTree/Expression/LocalVarIdentifier.java b/src/main/java/abstractSyntaxTree/Expression/LocalVarIdentifier.java index 3b622e6..aac2115 100644 --- a/src/main/java/abstractSyntaxTree/Expression/LocalVarIdentifier.java +++ b/src/main/java/abstractSyntaxTree/Expression/LocalVarIdentifier.java @@ -45,7 +45,7 @@ public class LocalVarIdentifier extends AbstractType implements IExpression{ } @Override - public void codeGen(MethodVisitor mv, LinkedHashMap localVars, HashMap> typeContext) throws Exception { + public void codeGen(MethodVisitor mv, LinkedHashMap localVars, HashMap> typeContext, HashMap>> methodContext) throws Exception { // Check if the variable is in the list of local variables String type = localVars.get(identifier); if (type == null){ diff --git a/src/main/java/abstractSyntaxTree/Expression/UnaryExpression.java b/src/main/java/abstractSyntaxTree/Expression/UnaryExpression.java index 4a2243c..5577cc7 100644 --- a/src/main/java/abstractSyntaxTree/Expression/UnaryExpression.java +++ b/src/main/java/abstractSyntaxTree/Expression/UnaryExpression.java @@ -15,8 +15,8 @@ import java.util.Objects; public class UnaryExpression extends AbstractType implements IExpression{ public String operator; - public IDatatype operand; - public UnaryExpression(String operator, IDatatype operand){ + public IExpression operand; + public UnaryExpression(String operator, IExpression operand){ this.operator = operator; this.operand = operand; } @@ -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) { @@ -51,9 +51,9 @@ public class UnaryExpression extends AbstractType implements IExpression{ } @Override - public void codeGen(MethodVisitor mv, LinkedHashMap localVars, HashMap> typeContext) throws Exception { + 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/Statement/BlockStatement.java b/src/main/java/abstractSyntaxTree/Statement/BlockStatement.java index b0f0e48..477cbfa 100644 --- a/src/main/java/abstractSyntaxTree/Statement/BlockStatement.java +++ b/src/main/java/abstractSyntaxTree/Statement/BlockStatement.java @@ -107,7 +107,7 @@ public class BlockStatement extends AbstractType implements IStatement { } @Override - public void codeGen(MethodVisitor mv, LinkedHashMap localVars, HashMap> typeContext) throws Exception { + public void codeGen(MethodVisitor mv, LinkedHashMap localVars, HashMap> typeContext, HashMap>> methodContext) 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 @@ -115,7 +115,7 @@ public class BlockStatement extends AbstractType implements IStatement { LinkedHashMap blockLocalVars = new LinkedHashMap<>(localVars); for (IStatement statement : statements) { - statement.codeGen(mv, blockLocalVars, typeContext); + statement.codeGen(mv, blockLocalVars, typeContext, methodContext); } } diff --git a/src/main/java/abstractSyntaxTree/Statement/EmptyStatement.java b/src/main/java/abstractSyntaxTree/Statement/EmptyStatement.java index 5a91eef..021ac6f 100644 --- a/src/main/java/abstractSyntaxTree/Statement/EmptyStatement.java +++ b/src/main/java/abstractSyntaxTree/Statement/EmptyStatement.java @@ -20,7 +20,7 @@ public class EmptyStatement extends AbstractType implements IStatement{ } @Override - public void codeGen(MethodVisitor mv, LinkedHashMap localVars, HashMap> typeContext) throws Exception { + public void codeGen(MethodVisitor mv, LinkedHashMap localVars, HashMap> typeContext, HashMap>> methodContext) 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 a270b60..cbc0a76 100644 --- a/src/main/java/abstractSyntaxTree/Statement/IStatement.java +++ b/src/main/java/abstractSyntaxTree/Statement/IStatement.java @@ -14,6 +14,6 @@ public interface IStatement extends Node { TypeCheckResult typeCheck(HashMap>> methodContext, HashMap> typeContext, HashMap localVars) throws TypeCheckException; - void codeGen(MethodVisitor mv, LinkedHashMap localVars, HashMap> typeContext) throws Exception; + void codeGen(MethodVisitor mv, LinkedHashMap localVars, HashMap> typeContext, HashMap>> methodContext) throws Exception; TypeCheckResult getTypeCheckResult(); } diff --git a/src/main/java/abstractSyntaxTree/Statement/IfElseStatement.java b/src/main/java/abstractSyntaxTree/Statement/IfElseStatement.java index af055c4..d380fae 100644 --- a/src/main/java/abstractSyntaxTree/Statement/IfElseStatement.java +++ b/src/main/java/abstractSyntaxTree/Statement/IfElseStatement.java @@ -56,21 +56,21 @@ public class IfElseStatement extends AbstractType implements IStatement{ @Override - public void codeGen(MethodVisitor mv, LinkedHashMap localVars, HashMap> typeContext) throws Exception { + public void codeGen(MethodVisitor mv, LinkedHashMap localVars, HashMap> typeContext, HashMap>> methodContext) throws Exception { LinkedHashMap blockLocalVars = new LinkedHashMap<>(localVars); Label conditionFalse = new Label(); Label statementEnd = new Label(); - condition.codeGen(mv, localVars, typeContext); + condition.codeGen(mv, localVars, typeContext, methodContext); mv.visitJumpInsn(Opcodes.IFEQ, conditionFalse); //Checks if the condition is false (0) - ifStatement.codeGen(mv, blockLocalVars, typeContext); //If the condition is true, execute the ifBlock + ifStatement.codeGen(mv, blockLocalVars, typeContext, methodContext); //If the condition is true, execute the ifBlock mv.visitJumpInsn(Opcodes.GOTO, statementEnd); //Jump to the end of the if-else statement mv.visitLabel(conditionFalse); - elseStatement.codeGen(mv, blockLocalVars, typeContext); //If the condition is false, execute the elseBlock + elseStatement.codeGen(mv, blockLocalVars, typeContext, methodContext); //If the condition is false, execute the elseBlock mv.visitLabel(statementEnd); //End of the if-else statement diff --git a/src/main/java/abstractSyntaxTree/Statement/IfStatement.java b/src/main/java/abstractSyntaxTree/Statement/IfStatement.java index 0084276..be39432 100644 --- a/src/main/java/abstractSyntaxTree/Statement/IfStatement.java +++ b/src/main/java/abstractSyntaxTree/Statement/IfStatement.java @@ -43,16 +43,16 @@ public class IfStatement extends AbstractType implements IStatement{ } @Override - public void codeGen(MethodVisitor mv, LinkedHashMap localVars, HashMap> typeContext) throws Exception { + public void codeGen(MethodVisitor mv, LinkedHashMap localVars, HashMap> typeContext, HashMap>> methodContext) throws Exception { LinkedHashMap blockLocalVars = new LinkedHashMap<>(localVars); Label conditionFalse = new Label(); - condition.codeGen(mv, localVars, typeContext); + condition.codeGen(mv, localVars, typeContext, methodContext); mv.visitJumpInsn(Opcodes.IFEQ, conditionFalse); //Checks if the condition is false (0) - ifStatement.codeGen(mv, blockLocalVars, typeContext); + ifStatement.codeGen(mv, blockLocalVars, typeContext, methodContext); mv.visitLabel(conditionFalse); // If the condition is false, the Statements in the ifBlock will not be executed } diff --git a/src/main/java/abstractSyntaxTree/Statement/LocalVarDecl.java b/src/main/java/abstractSyntaxTree/Statement/LocalVarDecl.java index 5fbb3cb..5413556 100644 --- a/src/main/java/abstractSyntaxTree/Statement/LocalVarDecl.java +++ b/src/main/java/abstractSyntaxTree/Statement/LocalVarDecl.java @@ -47,27 +47,40 @@ public class LocalVarDecl extends AbstractType implements IStatement{ } @Override - public void codeGen(MethodVisitor mv, LinkedHashMap localVars, HashMap> typeContext) throws Exception { + public void codeGen(MethodVisitor mv, LinkedHashMap localVars, HashMap> typeContext, HashMap>> methodContext) throws Exception { localVars.put(identifier, type); + int index = localVars.size() - 1; - int index = localVars.size()-1; + if (expression != null) { + expression.codeGen(mv, localVars, typeContext,methodContext); - // Set a default value for the variable --> less problems - switch (type){ - case "int": - mv.visitInsn(Opcodes.ICONST_0); - mv.visitVarInsn(Opcodes.ISTORE, index); - break; - case "boolean": - mv.visitInsn(Opcodes.ICONST_0); - mv.visitVarInsn(Opcodes.ISTORE, index); - break; - case "void": - break; - default: - mv.visitInsn(Opcodes.ACONST_NULL); - mv.visitVarInsn(Opcodes.ASTORE, index); + // Store the result in the local variable + switch (type){ + case "int", "char", "boolean": + mv.visitVarInsn(Opcodes.ISTORE, index); + break; + default: + mv.visitVarInsn(Opcodes.ASTORE, index); + } + } else { + + // Set a default value for the variable --> less problems + switch (type) { + case "int": + mv.visitInsn(Opcodes.ICONST_1); + mv.visitVarInsn(Opcodes.ISTORE, index); + break; + case "boolean": + mv.visitInsn(Opcodes.ICONST_0); + mv.visitVarInsn(Opcodes.ISTORE, index); + break; + case "void": + break; + default: + mv.visitInsn(Opcodes.ACONST_NULL); + mv.visitVarInsn(Opcodes.ASTORE, index); + } } } diff --git a/src/main/java/abstractSyntaxTree/Statement/ReturnStatement.java b/src/main/java/abstractSyntaxTree/Statement/ReturnStatement.java index b9a64e4..c40a370 100644 --- a/src/main/java/abstractSyntaxTree/Statement/ReturnStatement.java +++ b/src/main/java/abstractSyntaxTree/Statement/ReturnStatement.java @@ -38,12 +38,11 @@ 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, LinkedHashMap localVars, HashMap> typeContext) throws Exception { + public void codeGen(MethodVisitor mv, LinkedHashMap localVars, HashMap> typeContext, HashMap>> methodContext) throws Exception { if (expression != null) { - expression.codeGen(mv, localVars, typeContext); + expression.codeGen(mv, localVars, typeContext, methodContext); //Get the Type of the expression - //TODO: Resolve how do we get the type of the expression String type = expression.getTypeCheckResult().type; if (type.equals("int") || type.equals("boolean") || type.equals("char")) { diff --git a/src/main/java/abstractSyntaxTree/Statement/WhileStatement.java b/src/main/java/abstractSyntaxTree/Statement/WhileStatement.java index bf61905..47255ea 100644 --- a/src/main/java/abstractSyntaxTree/Statement/WhileStatement.java +++ b/src/main/java/abstractSyntaxTree/Statement/WhileStatement.java @@ -42,7 +42,7 @@ public class WhileStatement extends AbstractType implements IStatement { } @Override - public void codeGen(MethodVisitor mv, LinkedHashMap localVars, HashMap> typeContext) throws Exception { + public void codeGen(MethodVisitor mv, LinkedHashMap localVars, HashMap> typeContext, HashMap>> methodContext) throws Exception { LinkedHashMap blockLocalVars = new LinkedHashMap<>(localVars); @@ -51,10 +51,10 @@ public class WhileStatement extends AbstractType implements IStatement { mv.visitLabel(LoopStart); - condition.codeGen(mv, localVars, typeContext); + condition.codeGen(mv, localVars, typeContext, methodContext); mv.visitJumpInsn(Opcodes.IFEQ, conditionFalse); // Checks if the condition is false (0) - statement.codeGen(mv, blockLocalVars, typeContext); + statement.codeGen(mv, blockLocalVars, typeContext, methodContext); //statement.codeGen(mv); //TODO: If the block ends with a return statement, we might have to pop it from the stack // So the next iteration starts with a clean stack diff --git a/src/main/java/abstractSyntaxTree/StatementExpression/AssignStatementExpression.java b/src/main/java/abstractSyntaxTree/StatementExpression/AssignStatementExpression.java index 7e6f0a0..0f40fca 100644 --- a/src/main/java/abstractSyntaxTree/StatementExpression/AssignStatementExpression.java +++ b/src/main/java/abstractSyntaxTree/StatementExpression/AssignStatementExpression.java @@ -66,12 +66,12 @@ public class AssignStatementExpression extends AbstractType implements IExpressi } @Override - public void codeGen(MethodVisitor mv, LinkedHashMap localVars, HashMap> typeContext) throws Exception { + public void codeGen(MethodVisitor mv, LinkedHashMap localVars, HashMap> typeContext, HashMap>> methodContext) throws Exception { //TODO: Do we need the value on the stack after assigning it? //TODO: WE do not differentiate between InstanceVar and FieldVar // Call the codeGen on the right expression which will push the value of the right expression onto the stack - right.codeGen(mv, localVars, typeContext); + right.codeGen(mv, localVars, typeContext, methodContext); if (left instanceof LocalVarIdentifier) { LocalVarIdentifier localVar = (LocalVarIdentifier) left; diff --git a/src/main/java/abstractSyntaxTree/StatementExpression/MethodCallStatementExpression.java b/src/main/java/abstractSyntaxTree/StatementExpression/MethodCallStatementExpression.java index f34de98..2d10bc9 100644 --- a/src/main/java/abstractSyntaxTree/StatementExpression/MethodCallStatementExpression.java +++ b/src/main/java/abstractSyntaxTree/StatementExpression/MethodCallStatementExpression.java @@ -79,51 +79,96 @@ public class MethodCallStatementExpression extends AbstractType implements IExpr } //Errors occur due to the change in parameter in the RefType class - // I need the methodContext here to get the method descriptor @Override - public void codeGen(MethodVisitor mv, LinkedHashMap localVars, HashMap> typeContext) throws Exception { - //Generate Bytecode for the receiver - if (receiver.thisExpression) { - // If the receiver is "this" then load "this" onto the stack - mv.visitVarInsn(Opcodes.ALOAD, 0); - } else if (receiver.instVarExpression != null) { - receiver.instVarExpression.codeGen(mv, localVars, typeContext); + public void codeGen(MethodVisitor mv, LinkedHashMap localVars, HashMap> typeContext, HashMap>> methodContext) throws Exception { + String owner; - } else if (receiver.newStatementExpression != null) { - receiver.newStatementExpression.codeGen(mv, localVars, typeContext); - - // Not sure about this part - } else if (receiver.identifier != null) { - // Load local variable onto the stack - for (String key : localVars.keySet()) { - if (key.equals(receiver.identifier)) { - String type = localVars.get(key); + // 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, Integer.parseInt(key)); - break; + 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; } } - - // Generate Bytecode for the arguments - for (IExpression argument : arguments) { - argument.codeGen(mv, localVars, typeContext); - } - - - String descriptor; - // List methodDecls = thisClass.methodDecls; -// for (MethodDecl methodDecl : methodDecls) { -// if (methodDecl.name.equals(methodName)) { -// //Get the method descriptor -// //descriptor = methodDecl.getMethodDescriptor(methodContext); //methodContext is missing -// } -// } - // Invoke the method -// String className = classThatHasTheMethodIfNotThis != null ? classThatHasTheMethodIfNotThis.name : thisClass.name; - //mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, className, methodName, descriptor, false); + descriptor.append(")"); // Methods always return void + return descriptor.toString(); } + @Override public boolean equals(Object o) { if (this == o) return true; diff --git a/src/main/java/abstractSyntaxTree/StatementExpression/NewStatementExpression.java b/src/main/java/abstractSyntaxTree/StatementExpression/NewStatementExpression.java index 4188fbd..4b2bc3f 100644 --- a/src/main/java/abstractSyntaxTree/StatementExpression/NewStatementExpression.java +++ b/src/main/java/abstractSyntaxTree/StatementExpression/NewStatementExpression.java @@ -39,7 +39,7 @@ public class NewStatementExpression extends AbstractType implements IExpression, } @Override - public void codeGen(MethodVisitor mv, LinkedHashMap localVars, HashMap> typeContext) throws Exception { + public void codeGen(MethodVisitor mv, LinkedHashMap localVars, HashMap> typeContext, HashMap>> methodContext) throws Exception { //Create new instance of the class mv.visitTypeInsn(Opcodes.NEW, className); @@ -47,7 +47,7 @@ public class NewStatementExpression extends AbstractType implements IExpression, mv.visitInsn(Opcodes.DUP); for (IExpression argument : arguments) { - argument.codeGen(mv, localVars, typeContext); + argument.codeGen(mv, localVars, typeContext, methodContext); } String descriptor = getConstructorDescriptor(); @@ -59,7 +59,8 @@ public class NewStatementExpression extends AbstractType implements IExpression, } private String getConstructorDescriptor() { - StringBuilder descriptor = new StringBuilder(); + StringBuilder descriptor = new StringBuilder("("); + for (IExpression parameter : arguments) { TypeCheckResult result = parameter.getTypeCheckResult(); diff --git a/src/main/java/astGenerator/ASTGenerator.java b/src/main/java/astGenerator/ASTGenerator.java index 3d7d34e..980fc01 100644 --- a/src/main/java/astGenerator/ASTGenerator.java +++ b/src/main/java/astGenerator/ASTGenerator.java @@ -271,7 +271,8 @@ public class ASTGenerator extends DecafBaseVisitor { } else if (ctx.value() != null) { return visitValue(ctx.value()); } else if (ctx.binaryExpr() != null) { - //todo + IExpression expression = (IExpression) visit(ctx.binaryExpr()); + return new UnaryExpression("!", expression); } return null; }