From 2f549e31e9083e86d69fc89b8b06aec55cdb8740 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krau=C3=9F=2C=20Josefine?= Date: Tue, 14 May 2024 14:45:04 +0200 Subject: [PATCH 1/8] interface changes, added localvaridentifier, removed iclass interface, some type check for statements, delete varrefexpression --- src/main/java/ASTGenerator.java | 2 -- src/main/java/Compiler.java | 18 ++++++++++ src/main/java/Input.java | 6 ++-- src/main/java/TestClass.java | 6 ++++ src/main/java/TypeCheck/TypeCheckHelper.java | 3 +- .../abstractSyntaxTree/Class/FieldDecl.java | 3 +- .../java/abstractSyntaxTree/Class/IClass.java | 16 --------- .../abstractSyntaxTree/Class/MethodDecl.java | 11 +++--- .../abstractSyntaxTree/Class/RefType.java | 7 ++-- ...xpression.java => LocalVarIdentifier.java} | 16 +++++---- .../Expression/UnaryExpression.java | 9 +++-- src/main/java/abstractSyntaxTree/Program.java | 10 +++--- .../Statement/BlockStatement.java | 27 ++++++-------- .../Statement/EmptyStatement.java | 14 ++------ .../Statement/IStatement.java | 11 ++---- .../Statement/IfElseStatement.java | 18 +++------- .../Statement/IfStatement.java | 16 +++------ .../Statement/LocalVarDecl.java | 35 ++++++++++++++++++ .../Statement/ReturnStatement.java | 14 ++------ .../Statement/WhileStatement.java | 15 ++------ .../AssignStatementExpression.java | 36 ++++++++++++------- .../MethodCallStatementExpression.java | 7 ++-- .../NewStatementExpression.java | 8 ++--- 23 files changed, 156 insertions(+), 152 deletions(-) create mode 100644 src/main/java/TestClass.java delete mode 100644 src/main/java/abstractSyntaxTree/Class/IClass.java rename src/main/java/abstractSyntaxTree/Expression/{VarRefExpression.java => LocalVarIdentifier.java} (52%) create mode 100644 src/main/java/abstractSyntaxTree/Statement/LocalVarDecl.java diff --git a/src/main/java/ASTGenerator.java b/src/main/java/ASTGenerator.java index 0d9570f..8629671 100644 --- a/src/main/java/ASTGenerator.java +++ b/src/main/java/ASTGenerator.java @@ -1,5 +1,4 @@ import abstractSyntaxTree.Class.FieldDecl; -import abstractSyntaxTree.Class.IClass; import abstractSyntaxTree.Class.MethodDecl; import abstractSyntaxTree.Class.RefType; import abstractSyntaxTree.Expression.BinaryExpression; @@ -11,7 +10,6 @@ import abstractSyntaxTree.Statement.*; import gen.DecafBaseVisitor; import gen.DecafParser; -import java.beans.Expression; import java.util.ArrayList; import java.util.List; diff --git a/src/main/java/Compiler.java b/src/main/java/Compiler.java index 28e65da..8d3fd73 100644 --- a/src/main/java/Compiler.java +++ b/src/main/java/Compiler.java @@ -1,5 +1,14 @@ import abstractSyntaxTree.Class.RefType; +import abstractSyntaxTree.Datatype.BoolDatatype; +import abstractSyntaxTree.Datatype.IntDatatype; +import abstractSyntaxTree.Expression.InstVarExpression; +import abstractSyntaxTree.Expression.LocalVarIdentifier; +import abstractSyntaxTree.Expression.UnaryExpression; import abstractSyntaxTree.Program; +import abstractSyntaxTree.Statement.IStatement; +import abstractSyntaxTree.Statement.LocalVarDecl; +import abstractSyntaxTree.Statement.ReturnStatement; +import abstractSyntaxTree.StatementExpression.AssignStatementExpression; import gen.DecafLexer; import gen.DecafParser; import org.antlr.v4.runtime.CharStream; @@ -81,6 +90,15 @@ public class Compiler { // System.out.println(refType.name); // } + abstractSyntaxTree.classes.get(1).methodDecls.get(0).codeBlock.returnType = "int"; + List statementsList = abstractSyntaxTree.classes.get(1).methodDecls.get(0).codeBlock.statements; + statementsList.add(new LocalVarDecl("int", "localInt")); + statementsList.add(new LocalVarDecl("bool", "localBool")); + statementsList.add(new LocalVarDecl("char", "localChar")); + statementsList.add(new AssignStatementExpression("=", new LocalVarIdentifier("localInt"), new UnaryExpression("", new IntDatatype()))); + //statementsList.add(new AssignStatementExpression("=", new InstVarExpression(abstractSyntaxTree.classes.get(1)), new UnaryExpression("instVarBool", new BoolDatatype()))); + + abstractSyntaxTree.classes.get(1).methodDecls.get(0).codeBlock.statements.add(new ReturnStatement(new UnaryExpression("", new IntDatatype()))); abstractSyntaxTree.typeCheck(); abstractSyntaxTree.codeGen(); diff --git a/src/main/java/Input.java b/src/main/java/Input.java index 034e89e..ea16d77 100644 --- a/src/main/java/Input.java +++ b/src/main/java/Input.java @@ -5,7 +5,9 @@ class Example { } class Example2 { - int i; - boolean j; + boolean instVarBool; + void m(int i){ + return; + } } diff --git a/src/main/java/TestClass.java b/src/main/java/TestClass.java new file mode 100644 index 0000000..39c1383 --- /dev/null +++ b/src/main/java/TestClass.java @@ -0,0 +1,6 @@ +public class TestClass { + public static void main(String[] args){ + new Example(); + new Example2(); + } +} diff --git a/src/main/java/TypeCheck/TypeCheckHelper.java b/src/main/java/TypeCheck/TypeCheckHelper.java index 5d487d8..b62cd43 100644 --- a/src/main/java/TypeCheck/TypeCheckHelper.java +++ b/src/main/java/TypeCheck/TypeCheckHelper.java @@ -12,8 +12,9 @@ public class TypeCheckHelper { if(type1Primitiv && type2Primitiv){ if(Objects.equals(type1, type2)){ result = type1; + }else{ + throw new Exception("no upper bound"); } - throw new Exception("no upper bound"); }else if(type1Primitiv || type2Primitiv){ throw new Exception("no upper bound"); }else{ diff --git a/src/main/java/abstractSyntaxTree/Class/FieldDecl.java b/src/main/java/abstractSyntaxTree/Class/FieldDecl.java index 0e2e0c1..54c0951 100644 --- a/src/main/java/abstractSyntaxTree/Class/FieldDecl.java +++ b/src/main/java/abstractSyntaxTree/Class/FieldDecl.java @@ -13,7 +13,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; -public class FieldDecl extends AbstractType implements IClass, Node { +public class FieldDecl extends AbstractType implements Node { public String type; // from parser public String identifier; // from parser @@ -39,7 +39,6 @@ public class FieldDecl extends AbstractType implements IClass, Node { return null; } - @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); diff --git a/src/main/java/abstractSyntaxTree/Class/IClass.java b/src/main/java/abstractSyntaxTree/Class/IClass.java deleted file mode 100644 index e71c991..0000000 --- a/src/main/java/abstractSyntaxTree/Class/IClass.java +++ /dev/null @@ -1,16 +0,0 @@ -package abstractSyntaxTree.Class; - -import TypeCheck.TypeCheckResult; -import org.objectweb.asm.ClassWriter; -import org.objectweb.asm.TypeReference; - -import java.util.HashMap; -import java.util.List; - -public interface IClass { - // visit method for code generation - - - void codeGen(ClassWriter cw) throws Exception; - -} diff --git a/src/main/java/abstractSyntaxTree/Class/MethodDecl.java b/src/main/java/abstractSyntaxTree/Class/MethodDecl.java index a1fc503..9348e38 100644 --- a/src/main/java/abstractSyntaxTree/Class/MethodDecl.java +++ b/src/main/java/abstractSyntaxTree/Class/MethodDecl.java @@ -14,7 +14,7 @@ import java.util.List; import java.util.Map; import java.util.Stack; -public class MethodDecl implements IClass, Node { +public class MethodDecl implements Node { //Class Name public String classThatContainsMethod; @@ -36,14 +36,15 @@ public class MethodDecl implements IClass, Node { this.localVars = new HashMap<>(); } - public TypeCheckResult typeCheck(HashMap>>> methodContext, HashMap> typeContext) throws Exception { + public TypeCheckResult typeCheck(HashMap>> methodContext, HashMap> typeContext) throws Exception { // jede methode als block statement aufrufen und jede neue locale varibale in localvars schreiben - codeBlock.typeCheck(methodContext, typeContext); - return null; + TypeCheckResult result = new TypeCheckResult(); + codeBlock.typeCheck(methodContext, typeContext, localVars); + result.type = codeBlock.returnType; + return result; } - @Override public void codeGen(ClassWriter cw) throws Exception { localVars.put("this", classThatContainsMethod); diff --git a/src/main/java/abstractSyntaxTree/Class/RefType.java b/src/main/java/abstractSyntaxTree/Class/RefType.java index 7702d36..83ef3a2 100644 --- a/src/main/java/abstractSyntaxTree/Class/RefType.java +++ b/src/main/java/abstractSyntaxTree/Class/RefType.java @@ -3,6 +3,7 @@ package abstractSyntaxTree.Class; import TypeCheck.AbstractType; import TypeCheck.TypeCheckResult; import abstractSyntaxTree.Node; +import abstractSyntaxTree.Parameter.ParameterList; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.Opcodes; @@ -10,7 +11,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; -public class RefType extends AbstractType implements IClass, Node { +public class RefType extends AbstractType implements Node { //Class Name public String name; @@ -29,7 +30,7 @@ public class RefType extends AbstractType implements IClass, Node { this.hasMain = hasMain; } - public TypeCheckResult typeCheck(HashMap>>> methodContext, + public TypeCheckResult typeCheck(HashMap>> methodContext, HashMap> typeContext) throws Exception { TypeCheckResult result = new TypeCheckResult(); @@ -72,7 +73,7 @@ public class RefType extends AbstractType implements IClass, Node { // Method for code generation which iterates over all the field declarations // and method declarations and calls their CodeGen methods - @Override + public void codeGen(ClassWriter cw) throws Exception { cw.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC, name, null, diff --git a/src/main/java/abstractSyntaxTree/Expression/VarRefExpression.java b/src/main/java/abstractSyntaxTree/Expression/LocalVarIdentifier.java similarity index 52% rename from src/main/java/abstractSyntaxTree/Expression/VarRefExpression.java rename to src/main/java/abstractSyntaxTree/Expression/LocalVarIdentifier.java index 9276930..7c1888a 100644 --- a/src/main/java/abstractSyntaxTree/Expression/VarRefExpression.java +++ b/src/main/java/abstractSyntaxTree/Expression/LocalVarIdentifier.java @@ -1,15 +1,19 @@ package abstractSyntaxTree.Expression; +import TypeCheck.TypeCheckHelper; import TypeCheck.TypeCheckResult; import org.objectweb.asm.MethodVisitor; -import java.util.Map; +public class LocalVarIdentifier implements IExpression{ -public class VarRefExpression implements IExpression{ + String identifier; + public LocalVarIdentifier(String identifier){ + this.identifier = identifier; + } - //Parameters that are needed here - private String varName; - private Map localVars; + public String getIdentifier() { + return identifier; + } @Override public TypeCheckResult typeCheck() throws Exception { @@ -18,6 +22,6 @@ public class VarRefExpression implements IExpression{ @Override public void codeGen(MethodVisitor mv) throws Exception { - throw new Exception("CodeGen not implemented for VarRefExpression"); + } } diff --git a/src/main/java/abstractSyntaxTree/Expression/UnaryExpression.java b/src/main/java/abstractSyntaxTree/Expression/UnaryExpression.java index 4acdc53..6fb57f9 100644 --- a/src/main/java/abstractSyntaxTree/Expression/UnaryExpression.java +++ b/src/main/java/abstractSyntaxTree/Expression/UnaryExpression.java @@ -12,6 +12,10 @@ import java.util.Objects; public class UnaryExpression extends AbstractType implements IExpression{ public String operator; public IDatatype operand; + public UnaryExpression(String operator, IDatatype operand){ + this.operator = operator; + this.operand = operand; + } @Override public TypeCheckResult typeCheck() throws Exception { TypeCheckResult result = new TypeCheckResult(); @@ -29,12 +33,13 @@ public class UnaryExpression extends AbstractType implements IExpression{ } case "-": - case "+": + case "": + case "+":{ if (Objects.equals(operandType, "int")){ result.type = "int"; } break; - + } } setTypeCheckResult(result); diff --git a/src/main/java/abstractSyntaxTree/Program.java b/src/main/java/abstractSyntaxTree/Program.java index ed2750e..95ba437 100644 --- a/src/main/java/abstractSyntaxTree/Program.java +++ b/src/main/java/abstractSyntaxTree/Program.java @@ -4,6 +4,8 @@ import TypeCheck.TypeCheckResult; import abstractSyntaxTree.Class.FieldDecl; import abstractSyntaxTree.Class.MethodDecl; import abstractSyntaxTree.Class.RefType; +import abstractSyntaxTree.Parameter.Parameter; +import abstractSyntaxTree.Parameter.ParameterList; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.Opcodes; @@ -18,7 +20,7 @@ import java.util.jar.JarOutputStream; public class Program implements Node { public List classes; public HashMap> typeContext; // (class, (type, identifier)) - public HashMap>>> methodContext; // (class, (returntype, (identifier, parameter))) + public HashMap>> methodContext; // (class, (returntype, (identifier, parameter))) public Program(List classes){ this.classes = classes; @@ -39,11 +41,11 @@ public class Program implements Node { typeContext.put(oneClass.name, classVars); // build method context - HashMap> methodIdentifierAndParameter = new HashMap<>(); - HashMap>> returnTypeAndMethod = new HashMap<>(); + HashMap methodIdentifierAndParameter = new HashMap<>(); + HashMap> returnTypeAndMethod = new HashMap<>(); for (MethodDecl methodDecl : oneClass.methodDecls){ - methodIdentifierAndParameter.put(methodDecl.name, (List) methodDecl.parameters); + methodIdentifierAndParameter.put(methodDecl.name, methodDecl.parameters); returnTypeAndMethod.put(methodDecl.returnType, methodIdentifierAndParameter); } methodContext.put(oneClass.name, returnTypeAndMethod); diff --git a/src/main/java/abstractSyntaxTree/Statement/BlockStatement.java b/src/main/java/abstractSyntaxTree/Statement/BlockStatement.java index 039abbb..f0e3645 100644 --- a/src/main/java/abstractSyntaxTree/Statement/BlockStatement.java +++ b/src/main/java/abstractSyntaxTree/Statement/BlockStatement.java @@ -2,6 +2,8 @@ package abstractSyntaxTree.Statement; import TypeCheck.TypeCheckResult; import TypeCheck.AbstractType; +import abstractSyntaxTree.Class.FieldDecl; +import abstractSyntaxTree.Parameter.ParameterList; import org.objectweb.asm.*; import java.util.HashMap; @@ -11,8 +13,8 @@ public class BlockStatement extends AbstractType implements IStatement{ //We will need a parameter which holds the symbol table HashMap localVars; - String returnType; - List statements; + public String returnType; + public List statements; // do we need expression, statementexpression public BlockStatement(List statements, String returnType){ @@ -21,31 +23,24 @@ public class BlockStatement extends AbstractType implements IStatement{ } @Override - public TypeCheckResult typeCheck() throws Exception { - return null; - } - - @Override - public TypeCheckResult typeCheck(HashMap>>> methodContext, HashMap> typeContext, HashMap localVars) throws Exception { - return null; - } - - @Override - public TypeCheckResult typeCheck(HashMap>>> methodContext, HashMap> typeContext) throws Exception { + public TypeCheckResult typeCheck(HashMap>> methodContext, + HashMap> typeContext, + HashMap localVars) throws Exception { TypeCheckResult result = new TypeCheckResult(); if(statements.size() == 0){ result.type = "void"; } - TypeCheckResult blockType = new TypeCheckResult(); for (IStatement statement : statements) { TypeCheckResult typeOfCurrentStatement = statement.typeCheck(methodContext, typeContext, localVars); - if (!typeOfCurrentStatement.equals(this.returnType) && !blockType.equals("void")) { - throw new IllegalArgumentException("Block returns type that it should not return"); + if (!typeOfCurrentStatement.type.equals(this.returnType)) { + if(!typeOfCurrentStatement.type.equals("void")) + throw new Exception("TypeCheck Exception: Block returns the wrong type."); } } + result.type = this.returnType; // todo check if the block returns the needed return type in every case // todo ignore unreadchable statements? return result; diff --git a/src/main/java/abstractSyntaxTree/Statement/EmptyStatement.java b/src/main/java/abstractSyntaxTree/Statement/EmptyStatement.java index 774e0b7..a7ad544 100644 --- a/src/main/java/abstractSyntaxTree/Statement/EmptyStatement.java +++ b/src/main/java/abstractSyntaxTree/Statement/EmptyStatement.java @@ -2,26 +2,16 @@ package abstractSyntaxTree.Statement; import TypeCheck.TypeCheckResult; import TypeCheck.AbstractType; +import abstractSyntaxTree.Parameter.ParameterList; import org.objectweb.asm.MethodVisitor; import java.util.HashMap; import java.util.List; public class EmptyStatement extends AbstractType implements IStatement{ - @Override - public TypeCheckResult typeCheck() throws Exception { - TypeCheckResult result = new TypeCheckResult(); - result.type = "void"; - return result; - } @Override - public TypeCheckResult typeCheck(HashMap>>> methodContext, HashMap> typeContext, HashMap localVars) throws Exception { - return typeCheck(methodContext, typeContext); - } - - @Override - public TypeCheckResult typeCheck(HashMap>>> methodContext, HashMap> typeContext) throws Exception { + public TypeCheckResult typeCheck(HashMap>> methodContext, HashMap> typeContext, HashMap localVars) throws Exception { TypeCheckResult result = new TypeCheckResult(); result.type = "void"; return result; diff --git a/src/main/java/abstractSyntaxTree/Statement/IStatement.java b/src/main/java/abstractSyntaxTree/Statement/IStatement.java index 85918b5..2225532 100644 --- a/src/main/java/abstractSyntaxTree/Statement/IStatement.java +++ b/src/main/java/abstractSyntaxTree/Statement/IStatement.java @@ -2,6 +2,7 @@ package abstractSyntaxTree.Statement; import TypeCheck.TypeCheckResult; import abstractSyntaxTree.Node; +import abstractSyntaxTree.Parameter.ParameterList; import org.objectweb.asm.MethodVisitor; import java.util.HashMap; @@ -9,15 +10,7 @@ import java.util.List; public interface IStatement extends Node { - - - TypeCheckResult typeCheck() throws Exception; - - TypeCheckResult typeCheck(HashMap>>> methodContext, HashMap> typeContext, HashMap localVars) throws Exception; - - - TypeCheckResult typeCheck(HashMap>>> methodContext, HashMap> typeContext) throws Exception; - + TypeCheckResult typeCheck(HashMap>> methodContext, HashMap> typeContext, HashMap localVars) 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 b28086b..0a07c93 100644 --- a/src/main/java/abstractSyntaxTree/Statement/IfElseStatement.java +++ b/src/main/java/abstractSyntaxTree/Statement/IfElseStatement.java @@ -3,6 +3,7 @@ package abstractSyntaxTree.Statement; import TypeCheck.TypeCheckResult; import TypeCheck.AbstractType; import abstractSyntaxTree.Expression.IExpression; +import abstractSyntaxTree.Parameter.ParameterList; import org.objectweb.asm.*; import java.util.HashMap; @@ -19,8 +20,9 @@ public class IfElseStatement extends AbstractType implements IStatement{ this.elseStatement = elseStatement; } + @Override - public TypeCheckResult typeCheck() throws Exception { + public TypeCheckResult typeCheck(HashMap>> methodContext, HashMap> typeContext, HashMap localVars) throws Exception { TypeCheckResult result = new TypeCheckResult(); TypeCheckResult conditionType = condition.typeCheck(); @@ -29,8 +31,8 @@ public class IfElseStatement extends AbstractType implements IStatement{ throw new IllegalArgumentException("should be boolean"); } - TypeCheckResult ifStatementType = ifStatement.typeCheck(); - TypeCheckResult elseStatementType = elseStatement.typeCheck(); + TypeCheckResult ifStatementType = ifStatement.typeCheck(methodContext, typeContext, localVars); + TypeCheckResult elseStatementType = elseStatement.typeCheck(methodContext, typeContext, localVars); if (!ifStatementType.equals(elseStatementType)) { throw new IllegalArgumentException("if and else have different types"); @@ -40,16 +42,6 @@ public class IfElseStatement extends AbstractType implements IStatement{ return result; } - @Override - public TypeCheckResult typeCheck(HashMap>>> methodContext, HashMap> typeContext, HashMap localVars) throws Exception { - return null; - } - - @Override - public TypeCheckResult typeCheck(HashMap>>> methodContext, HashMap> typeContext) throws Exception { - return null; - } - @Override public void codeGen(MethodVisitor mv, HashMap localVars) throws Exception { diff --git a/src/main/java/abstractSyntaxTree/Statement/IfStatement.java b/src/main/java/abstractSyntaxTree/Statement/IfStatement.java index b51fe74..fc8c22d 100644 --- a/src/main/java/abstractSyntaxTree/Statement/IfStatement.java +++ b/src/main/java/abstractSyntaxTree/Statement/IfStatement.java @@ -3,6 +3,7 @@ package abstractSyntaxTree.Statement; import TypeCheck.TypeCheckResult; import TypeCheck.AbstractType; import abstractSyntaxTree.Expression.IExpression; +import abstractSyntaxTree.Parameter.ParameterList; import org.objectweb.asm.*; import java.util.HashMap; @@ -18,8 +19,9 @@ public class IfStatement extends AbstractType implements IStatement{ this.condition = condition; this.ifStatement = ifStatement; } + @Override - public TypeCheckResult typeCheck() throws Exception { + public TypeCheckResult typeCheck(HashMap>> methodContext, HashMap> typeContext, HashMap localVars) throws Exception { TypeCheckResult result = new TypeCheckResult(); TypeCheckResult conditionType = condition.typeCheck(); @@ -28,21 +30,11 @@ public class IfStatement extends AbstractType implements IStatement{ throw new Exception("TypeCheck Exception: Condition of If-Statement should be bool."); } - TypeCheckResult ifStatementType = ifStatement.typeCheck(); + TypeCheckResult ifStatementType = ifStatement.typeCheck(methodContext, typeContext, localVars); result.type = ifStatementType.type; return result; } - @Override - public TypeCheckResult typeCheck(HashMap>>> methodContext, HashMap> typeContext, HashMap localVars) throws Exception { - return null; - } - - @Override - public TypeCheckResult typeCheck(HashMap>>> methodContext, HashMap> typeContext) throws Exception { - return null; - } - @Override public void codeGen(MethodVisitor mv, HashMap localVars) throws Exception { diff --git a/src/main/java/abstractSyntaxTree/Statement/LocalVarDecl.java b/src/main/java/abstractSyntaxTree/Statement/LocalVarDecl.java new file mode 100644 index 0000000..4fd73a4 --- /dev/null +++ b/src/main/java/abstractSyntaxTree/Statement/LocalVarDecl.java @@ -0,0 +1,35 @@ +package abstractSyntaxTree.Statement; + +import TypeCheck.TypeCheckHelper; +import TypeCheck.TypeCheckResult; +import abstractSyntaxTree.Parameter.ParameterList; +import org.objectweb.asm.MethodVisitor; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; + +public class LocalVarDecl implements IStatement{ + String type; + String identifier; + public LocalVarDecl(String type, String identifier) { + this.type = type; + this.identifier = identifier; + } + @Override + public TypeCheckResult typeCheck(HashMap>> methodContext, HashMap> typeContext, HashMap localVars) throws Exception { + TypeCheckHelper.typeExists(this.type, new ArrayList<>(methodContext.keySet())); + + localVars.put(this.identifier, this.type); + + TypeCheckResult result = new TypeCheckResult(); + result.type = "void"; + return result; + } + + @Override + public void codeGen(MethodVisitor mv, HashMap localVars) throws Exception { + + } +} diff --git a/src/main/java/abstractSyntaxTree/Statement/ReturnStatement.java b/src/main/java/abstractSyntaxTree/Statement/ReturnStatement.java index 8e324d7..358ee25 100644 --- a/src/main/java/abstractSyntaxTree/Statement/ReturnStatement.java +++ b/src/main/java/abstractSyntaxTree/Statement/ReturnStatement.java @@ -3,6 +3,7 @@ package abstractSyntaxTree.Statement; import TypeCheck.TypeCheckResult; import TypeCheck.AbstractType; import abstractSyntaxTree.Expression.IExpression; +import abstractSyntaxTree.Parameter.ParameterList; import org.objectweb.asm.*; import java.util.HashMap; @@ -16,7 +17,7 @@ public class ReturnStatement extends AbstractType implements IStatement{ } @Override - public TypeCheckResult typeCheck() throws Exception { + public TypeCheckResult typeCheck(HashMap>> methodContext, HashMap> typeContext, HashMap localVars) throws Exception { TypeCheckResult result = new TypeCheckResult(); if (expression == null) { @@ -29,17 +30,6 @@ public class ReturnStatement extends AbstractType implements IStatement{ return result; } - @Override - public TypeCheckResult typeCheck(HashMap>>> methodContext, HashMap> typeContext, HashMap localVars) throws Exception { - return null; - } - - @Override - public TypeCheckResult typeCheck(HashMap>>> methodContext, HashMap> typeContext) throws Exception { - return null; - } - - //TODO: We do not differentiate between primitive types and reference types // 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 diff --git a/src/main/java/abstractSyntaxTree/Statement/WhileStatement.java b/src/main/java/abstractSyntaxTree/Statement/WhileStatement.java index b312be3..02d19e3 100644 --- a/src/main/java/abstractSyntaxTree/Statement/WhileStatement.java +++ b/src/main/java/abstractSyntaxTree/Statement/WhileStatement.java @@ -3,6 +3,7 @@ package abstractSyntaxTree.Statement; import TypeCheck.TypeCheckResult; import TypeCheck.AbstractType; import abstractSyntaxTree.Expression.IExpression; +import abstractSyntaxTree.Parameter.ParameterList; import org.objectweb.asm.*; import java.util.HashMap; @@ -18,7 +19,7 @@ public class WhileStatement extends AbstractType implements IStatement { } @Override - public TypeCheckResult typeCheck() throws Exception { + public TypeCheckResult typeCheck(HashMap>> methodContext, HashMap> typeContext, HashMap localVars) throws Exception { TypeCheckResult result = new TypeCheckResult(); TypeCheckResult conditionType = condition.typeCheck(); @@ -27,22 +28,12 @@ public class WhileStatement extends AbstractType implements IStatement { throw new IllegalArgumentException("Expected boolean"); } - TypeCheckResult statementType = statement.typeCheck(); + TypeCheckResult statementType = statement.typeCheck(methodContext, typeContext, localVars); result.type = statementType.type; return result; } - @Override - public TypeCheckResult typeCheck(HashMap>>> methodContext, HashMap> typeContext, HashMap localVars) throws Exception { - return null; - } - - @Override - public TypeCheckResult typeCheck(HashMap>>> methodContext, HashMap> typeContext) throws Exception { - return null; - } - @Override public void codeGen(MethodVisitor mv, HashMap localVars) throws Exception { Label conditionFalse = new Label(); diff --git a/src/main/java/abstractSyntaxTree/StatementExpression/AssignStatementExpression.java b/src/main/java/abstractSyntaxTree/StatementExpression/AssignStatementExpression.java index 8d96ae6..369557f 100644 --- a/src/main/java/abstractSyntaxTree/StatementExpression/AssignStatementExpression.java +++ b/src/main/java/abstractSyntaxTree/StatementExpression/AssignStatementExpression.java @@ -5,12 +5,12 @@ import TypeCheck.TypeCheckHelper; import TypeCheck.TypeCheckResult; import abstractSyntaxTree.Expression.IExpression; import abstractSyntaxTree.Expression.InstVarExpression; -import abstractSyntaxTree.Expression.VarRefExpression; +import abstractSyntaxTree.Expression.LocalVarIdentifier; +import abstractSyntaxTree.Parameter.ParameterList; import abstractSyntaxTree.Statement.IStatement; import org.objectweb.asm.*; import java.util.HashMap; -import java.util.List; import java.util.Objects; public class AssignStatementExpression extends AbstractType implements IExpression, IStatement { @@ -18,12 +18,27 @@ public class AssignStatementExpression extends AbstractType implements IExpressi public IExpression left; public IExpression right; + public AssignStatementExpression(String operator, IExpression leftExpression, IExpression rightExpression){ + this.operator = operator; + this.left = leftExpression; + this.right = rightExpression; + } + @Override - public TypeCheckResult typeCheck() throws Exception { + public TypeCheckResult typeCheck(HashMap>> methodContext, HashMap> typeContext, HashMap localVars) throws Exception { TypeCheckHelper helper = new TypeCheckHelper(); TypeCheckResult result = new TypeCheckResult(); TypeCheckResult leftType = left.typeCheck(); + if(leftType == null){ //left expression is the identifier of a var + leftType = new TypeCheckResult(); + if (left instanceof LocalVarIdentifier) { + LocalVarIdentifier localVarIdentifier = (LocalVarIdentifier) left; + String identifier = localVarIdentifier.getIdentifier(); + leftType.type = localVars.get(identifier); + } + // not local var + } TypeCheckResult rightType = right.typeCheck(); String upperbound = helper.upperBound(leftType.type, rightType.type); @@ -34,21 +49,16 @@ public class AssignStatementExpression extends AbstractType implements IExpressi return result; } - @Override - public TypeCheckResult typeCheck(HashMap>>> methodContext, HashMap> typeContext, HashMap localVars) throws Exception { - return null; - } - - @Override - public TypeCheckResult typeCheck(HashMap>>> methodContext, HashMap> typeContext) throws Exception { - return null; - } - @Override public void codeGen(MethodVisitor mv, HashMap localVars) throws Exception { } + @Override + public TypeCheckResult typeCheck() throws Exception { + return null; + } + @Override public void codeGen(MethodVisitor mv) throws Exception { left.codeGen(mv); diff --git a/src/main/java/abstractSyntaxTree/StatementExpression/MethodCallStatementExpression.java b/src/main/java/abstractSyntaxTree/StatementExpression/MethodCallStatementExpression.java index 1e6598a..0540422 100644 --- a/src/main/java/abstractSyntaxTree/StatementExpression/MethodCallStatementExpression.java +++ b/src/main/java/abstractSyntaxTree/StatementExpression/MethodCallStatementExpression.java @@ -5,6 +5,7 @@ import TypeCheck.TypeCheckResult; import abstractSyntaxTree.Class.MethodDecl; import abstractSyntaxTree.Class.RefType; import abstractSyntaxTree.Expression.IExpression; +import abstractSyntaxTree.Parameter.ParameterList; import abstractSyntaxTree.Statement.IStatement; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.MethodVisitor; @@ -44,13 +45,9 @@ public class MethodCallStatementExpression extends AbstractType implements IExpr return result; } - @Override - public TypeCheckResult typeCheck(HashMap>>> methodContext, HashMap> typeContext, HashMap localVars) throws Exception { - return null; - } @Override - public TypeCheckResult typeCheck(HashMap>>> methodContext, HashMap> typeContext) throws Exception { + public TypeCheckResult typeCheck(HashMap>> methodContext, HashMap> typeContext, HashMap localVars) throws Exception { return null; } diff --git a/src/main/java/abstractSyntaxTree/StatementExpression/NewStatementExpression.java b/src/main/java/abstractSyntaxTree/StatementExpression/NewStatementExpression.java index 63b7743..da19394 100644 --- a/src/main/java/abstractSyntaxTree/StatementExpression/NewStatementExpression.java +++ b/src/main/java/abstractSyntaxTree/StatementExpression/NewStatementExpression.java @@ -3,6 +3,7 @@ package abstractSyntaxTree.StatementExpression; import TypeCheck.AbstractType; import TypeCheck.TypeCheckResult; import abstractSyntaxTree.Expression.IExpression; +import abstractSyntaxTree.Parameter.ParameterList; import abstractSyntaxTree.Statement.IStatement; import org.objectweb.asm.MethodVisitor; @@ -15,13 +16,10 @@ public class NewStatementExpression extends AbstractType implements IExpression, return null; } - @Override - public TypeCheckResult typeCheck(HashMap>>> methodContext, HashMap> typeContext, HashMap localVars) throws Exception { - return null; - } + @Override - public TypeCheckResult typeCheck(HashMap>>> methodContext, HashMap> typeContext) throws Exception { + public TypeCheckResult typeCheck(HashMap>> methodContext, HashMap> typeContext, HashMap localVars) throws Exception { return null; } From f2260c7a73cdf61bc27e65107a971dcf037f38bf Mon Sep 17 00:00:00 2001 From: Jochen Seyfried Date: Tue, 14 May 2024 14:51:59 +0200 Subject: [PATCH 2/8] Deleted ICLass and updated the MethodDecl codeGen --- .../java/abstractSyntaxTree/Statement/IfElseStatement.java | 6 ++++-- .../StatementExpression/AssignStatementExpression.java | 3 +++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/main/java/abstractSyntaxTree/Statement/IfElseStatement.java b/src/main/java/abstractSyntaxTree/Statement/IfElseStatement.java index 0a07c93..a696fda 100644 --- a/src/main/java/abstractSyntaxTree/Statement/IfElseStatement.java +++ b/src/main/java/abstractSyntaxTree/Statement/IfElseStatement.java @@ -45,17 +45,19 @@ public class IfElseStatement extends AbstractType implements IStatement{ @Override public void codeGen(MethodVisitor mv, HashMap localVars) throws Exception { + HashMap blockLocalVars = new HashMap<>(localVars); + Label conditionFalse = new Label(); Label statementEnd = new Label(); condition.codeGen(mv); mv.visitJumpInsn(Opcodes.IFEQ, conditionFalse); //Checks if the condition is false (0) - ifStatement.codeGen(mv); //If the condition is true, execute the ifBlock + ifStatement.codeGen(mv, blockLocalVars); //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); //If the condition is false, execute the elseBlock + elseStatement.codeGen(mv, blockLocalVars); //If the condition is false, execute the elseBlock mv.visitLabel(statementEnd); //End of the if-else statement diff --git a/src/main/java/abstractSyntaxTree/StatementExpression/AssignStatementExpression.java b/src/main/java/abstractSyntaxTree/StatementExpression/AssignStatementExpression.java index 369557f..a8ec0c9 100644 --- a/src/main/java/abstractSyntaxTree/StatementExpression/AssignStatementExpression.java +++ b/src/main/java/abstractSyntaxTree/StatementExpression/AssignStatementExpression.java @@ -51,6 +51,9 @@ public class AssignStatementExpression extends AbstractType implements IExpressi @Override public void codeGen(MethodVisitor mv, HashMap localVars) throws Exception { + if (left instanceof VarRefExpression varRef) { + + } } From 0fcea195def7896e8a2e639ab2a70d3d8dc6f973 Mon Sep 17 00:00:00 2001 From: Jochen Seyfried Date: Tue, 14 May 2024 14:54:33 +0200 Subject: [PATCH 3/8] Updated If and WhileStatement --- src/main/java/abstractSyntaxTree/Statement/IfStatement.java | 4 +++- .../java/abstractSyntaxTree/Statement/WhileStatement.java | 5 ++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/main/java/abstractSyntaxTree/Statement/IfStatement.java b/src/main/java/abstractSyntaxTree/Statement/IfStatement.java index fc8c22d..cf57577 100644 --- a/src/main/java/abstractSyntaxTree/Statement/IfStatement.java +++ b/src/main/java/abstractSyntaxTree/Statement/IfStatement.java @@ -38,12 +38,14 @@ public class IfStatement extends AbstractType implements IStatement{ @Override public void codeGen(MethodVisitor mv, HashMap localVars) throws Exception { + HashMap blockLocalVars = new HashMap<>(localVars); + Label conditionFalse = new Label(); condition.codeGen(mv); mv.visitJumpInsn(Opcodes.IFEQ, conditionFalse); //Checks if the condition is false (0) - ifStatement.codeGen(mv); + ifStatement.codeGen(mv, blockLocalVars); 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/WhileStatement.java b/src/main/java/abstractSyntaxTree/Statement/WhileStatement.java index 02d19e3..e3648f9 100644 --- a/src/main/java/abstractSyntaxTree/Statement/WhileStatement.java +++ b/src/main/java/abstractSyntaxTree/Statement/WhileStatement.java @@ -36,6 +36,9 @@ public class WhileStatement extends AbstractType implements IStatement { @Override public void codeGen(MethodVisitor mv, HashMap localVars) throws Exception { + + HashMap blockLocalVars = new HashMap<>(localVars); + Label conditionFalse = new Label(); Label LoopStart = new Label(); @@ -44,7 +47,7 @@ public class WhileStatement extends AbstractType implements IStatement { condition.codeGen(mv); mv.visitJumpInsn(Opcodes.IFEQ, conditionFalse); // Checks if the condition is false (0) - statement.codeGen(mv); + statement.codeGen(mv, blockLocalVars); //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 mv.visitJumpInsn(Opcodes.GOTO, LoopStart); // Jump to the start of the while loop From a59950e186933cc8e68e4ce65fe8063a662eecf8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krau=C3=9F=2C=20Josefine?= Date: Tue, 14 May 2024 15:15:58 +0200 Subject: [PATCH 4/8] parameterlist, typecheck --- src/main/java/Compiler.java | 10 ++++++ src/main/java/Input.java | 4 +-- .../abstractSyntaxTree/Class/MethodDecl.java | 2 +- .../abstractSyntaxTree/Class/RefType.java | 5 +-- .../Expression/BinaryExpression.java | 12 +++---- .../Expression/IExpression.java | 6 +++- .../Expression/InstVarExpression.java | 13 ++++--- src/main/java/abstractSyntaxTree/Program.java | 12 +++---- .../Statement/IfElseStatement.java | 4 +-- .../Statement/IfStatement.java | 2 +- .../Statement/WhileStatement.java | 2 +- .../AssignStatementExpression.java | 34 +++++++++---------- .../MethodCallStatementExpression.java | 2 +- src/main/java/astGenerator/ASTGenerator.java | 2 +- 14 files changed, 64 insertions(+), 46 deletions(-) diff --git a/src/main/java/Compiler.java b/src/main/java/Compiler.java index 56fb082..b123157 100644 --- a/src/main/java/Compiler.java +++ b/src/main/java/Compiler.java @@ -91,6 +91,16 @@ public class Compiler { // System.out.println(refType.name); // } + abstractSyntaxTree.classes.get(1).methodDecls.get(0).codeBlock.returnType = "int"; + List statementsList = abstractSyntaxTree.classes.get(1).methodDecls.get(0).codeBlock.statements; + statementsList.remove(0); + statementsList.add(new LocalVarDecl("int", "localInt")); + statementsList.add(new LocalVarDecl("bool", "localBool")); + statementsList.add(new LocalVarDecl("char", "localChar")); + statementsList.add(new AssignStatementExpression("=", new LocalVarIdentifier("localInt"), new UnaryExpression("", new IntDatatype()))); + statementsList.add(new AssignStatementExpression("=", new InstVarExpression(abstractSyntaxTree.classes.get(1), "instVarBool"), new UnaryExpression("instVarBool", new BoolDatatype()))); + + abstractSyntaxTree.classes.get(1).methodDecls.get(0).codeBlock.statements.add(new ReturnStatement(new UnaryExpression("", new IntDatatype()))); abstractSyntaxTree.typeCheck(); abstractSyntaxTree.codeGen(); diff --git a/src/main/java/Input.java b/src/main/java/Input.java index ea16d77..a67c0d2 100644 --- a/src/main/java/Input.java +++ b/src/main/java/Input.java @@ -6,8 +6,6 @@ class Example { } class Example2 { boolean instVarBool; - void m(int i){ - return; - } + int m(int n){return 1;} } diff --git a/src/main/java/abstractSyntaxTree/Class/MethodDecl.java b/src/main/java/abstractSyntaxTree/Class/MethodDecl.java index 3517283..2707e9f 100644 --- a/src/main/java/abstractSyntaxTree/Class/MethodDecl.java +++ b/src/main/java/abstractSyntaxTree/Class/MethodDecl.java @@ -14,7 +14,7 @@ import java.util.List; import java.util.Map; import java.util.Stack; -public class MethodDecl implements IClass, Node { +public class MethodDecl implements Node { //Class Name public String classThatContainsMethod; diff --git a/src/main/java/abstractSyntaxTree/Class/RefType.java b/src/main/java/abstractSyntaxTree/Class/RefType.java index 68b139c..c50c817 100644 --- a/src/main/java/abstractSyntaxTree/Class/RefType.java +++ b/src/main/java/abstractSyntaxTree/Class/RefType.java @@ -3,6 +3,7 @@ package abstractSyntaxTree.Class; import TypeCheck.AbstractType; import TypeCheck.TypeCheckResult; import abstractSyntaxTree.Node; +import abstractSyntaxTree.Parameter.ParameterList; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.Opcodes; @@ -29,7 +30,7 @@ public class RefType extends AbstractType implements Node { this.hasMain = hasMain; } - public TypeCheckResult typeCheck(HashMap>>> methodContext, + public TypeCheckResult typeCheck(HashMap>> methodContext, HashMap> typeContext) throws Exception { TypeCheckResult result = new TypeCheckResult(); @@ -83,7 +84,7 @@ public class RefType extends AbstractType implements Node { } for (MethodDecl method : methodDecls) { - method.codeGen(cw); + // method.codeGen(cw); } cw.visitEnd(); } diff --git a/src/main/java/abstractSyntaxTree/Expression/BinaryExpression.java b/src/main/java/abstractSyntaxTree/Expression/BinaryExpression.java index 72af1be..ad619f9 100644 --- a/src/main/java/abstractSyntaxTree/Expression/BinaryExpression.java +++ b/src/main/java/abstractSyntaxTree/Expression/BinaryExpression.java @@ -37,7 +37,7 @@ public class BinaryExpression extends AbstractType implements IExpression{ case "<=": case ">=": case "!=": - result.type = helper.upperBound(leftType.type, rightType.type); + result.type = helper.upperBound(leftType.type, rightType.type); break; case "-": @@ -86,11 +86,11 @@ public class BinaryExpression extends AbstractType implements IExpression{ mv.visitJumpInsn(Opcodes.IFNE, operationTrue); break; - case "==": - // Keep in mind that only primitive types are allowed in this case (at this time) + case "==": + // Keep in mind that only primitive types are allowed in this case (at this time) - left.codeGen(mv); - right.codeGen(mv); + left.codeGen(mv); + right.codeGen(mv); mv.visitJumpInsn(Opcodes.IF_ICMPEQ, operationTrue); // If the two values are equal, jump to the end of the expression break; @@ -167,4 +167,4 @@ public class BinaryExpression extends AbstractType implements IExpression{ mv.visitLabel(expressionEnd); } -} +} \ No newline at end of file diff --git a/src/main/java/abstractSyntaxTree/Expression/IExpression.java b/src/main/java/abstractSyntaxTree/Expression/IExpression.java index a679711..1245400 100644 --- a/src/main/java/abstractSyntaxTree/Expression/IExpression.java +++ b/src/main/java/abstractSyntaxTree/Expression/IExpression.java @@ -1,11 +1,15 @@ package abstractSyntaxTree.Expression; import TypeCheck.TypeCheckResult; +import abstractSyntaxTree.Parameter.ParameterList; import org.objectweb.asm.MethodVisitor; +import java.util.HashMap; + public interface IExpression { // typeCheck method - TypeCheckResult typeCheck() throws Exception; + //TypeCheckResult typeCheck() throws Exception; + TypeCheckResult typeCheck(HashMap>> methodContext, HashMap> typeContext, HashMap localVars) throws Exception; // visit method for code generation void codeGen(MethodVisitor mv) throws Exception; diff --git a/src/main/java/abstractSyntaxTree/Expression/InstVarExpression.java b/src/main/java/abstractSyntaxTree/Expression/InstVarExpression.java index f7d58e3..6b9a261 100644 --- a/src/main/java/abstractSyntaxTree/Expression/InstVarExpression.java +++ b/src/main/java/abstractSyntaxTree/Expression/InstVarExpression.java @@ -2,9 +2,12 @@ package abstractSyntaxTree.Expression; import TypeCheck.TypeCheckResult; import abstractSyntaxTree.Class.RefType; +import abstractSyntaxTree.Parameter.ParameterList; import jdk.jshell.spi.ExecutionControl; import org.objectweb.asm.MethodVisitor; +import java.util.HashMap; + public class InstVarExpression implements IExpression{ //TODO: We have to decide upon more parameters and where they come from, for @@ -12,13 +15,15 @@ public class InstVarExpression implements IExpression{ private RefType classRef; private String fieldName; -/* public InstVarExpression(RefType classRef, String fieldName){ + public InstVarExpression(RefType classRef, String fieldName){ this.classRef = classRef; this.fieldName = fieldName; - }*/ + } + + @Override - public TypeCheckResult typeCheck() throws Exception { - return null; + public TypeCheckResult typeCheck(HashMap>> methodContext, HashMap> typeContext, HashMap localVars) throws Exception { + } @Override diff --git a/src/main/java/abstractSyntaxTree/Program.java b/src/main/java/abstractSyntaxTree/Program.java index e09bac6..fa9397b 100644 --- a/src/main/java/abstractSyntaxTree/Program.java +++ b/src/main/java/abstractSyntaxTree/Program.java @@ -20,7 +20,7 @@ import java.util.jar.JarOutputStream; public class Program implements Node { public List classes; public HashMap> typeContext; // (class, (type, identifier)) - public HashMap>> methodContext; // (class, (returntype, (identifier, parameterList))) + public HashMap>> methodContext; // (class, (returntype, (identifier, parameter))) public Program(List classes){ this.classes = classes; @@ -41,11 +41,11 @@ public class Program implements Node { typeContext.put(oneClass.name, classVars); // build method context - HashMap> methodIdentifierAndParameter = new HashMap<>(); - HashMap>> returnTypeAndMethod = new HashMap<>(); + HashMap methodIdentifierAndParameter = new HashMap<>(); + HashMap> returnTypeAndMethod = new HashMap<>(); for (MethodDecl methodDecl : oneClass.methodDecls){ - methodIdentifierAndParameter.put(methodDecl.name, (List) methodDecl.parameters); + methodIdentifierAndParameter.put(methodDecl.name, methodDecl.parameters); returnTypeAndMethod.put(methodDecl.returnType, methodIdentifierAndParameter); } methodContext.put(oneClass.name, returnTypeAndMethod); @@ -66,7 +66,7 @@ public class Program implements Node { ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); cw.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC, oneClass.name, null, "java/lang/Object", null); - oneClass.codeGen(cw, methodContext); + // oneClass.codeGen(cw); cw.visitEnd(); byte[] bytecode = cw.toByteArray(); @@ -102,4 +102,4 @@ public class Program implements Node { } */ } -} +} \ No newline at end of file diff --git a/src/main/java/abstractSyntaxTree/Statement/IfElseStatement.java b/src/main/java/abstractSyntaxTree/Statement/IfElseStatement.java index 0a07c93..650dfa1 100644 --- a/src/main/java/abstractSyntaxTree/Statement/IfElseStatement.java +++ b/src/main/java/abstractSyntaxTree/Statement/IfElseStatement.java @@ -51,11 +51,11 @@ public class IfElseStatement extends AbstractType implements IStatement{ condition.codeGen(mv); mv.visitJumpInsn(Opcodes.IFEQ, conditionFalse); //Checks if the condition is false (0) - ifStatement.codeGen(mv); //If the condition is true, execute the ifBlock + //ifStatement.codeGen(mv); //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); //If the condition is false, execute the elseBlock + //elseStatement.codeGen(mv); //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 fc8c22d..e38902e 100644 --- a/src/main/java/abstractSyntaxTree/Statement/IfStatement.java +++ b/src/main/java/abstractSyntaxTree/Statement/IfStatement.java @@ -43,7 +43,7 @@ public class IfStatement extends AbstractType implements IStatement{ condition.codeGen(mv); mv.visitJumpInsn(Opcodes.IFEQ, conditionFalse); //Checks if the condition is false (0) - ifStatement.codeGen(mv); + //ifStatement.codeGen(mv); 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/WhileStatement.java b/src/main/java/abstractSyntaxTree/Statement/WhileStatement.java index 02d19e3..9155fb5 100644 --- a/src/main/java/abstractSyntaxTree/Statement/WhileStatement.java +++ b/src/main/java/abstractSyntaxTree/Statement/WhileStatement.java @@ -44,7 +44,7 @@ public class WhileStatement extends AbstractType implements IStatement { condition.codeGen(mv); mv.visitJumpInsn(Opcodes.IFEQ, conditionFalse); // Checks if the condition is false (0) - statement.codeGen(mv); + //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 mv.visitJumpInsn(Opcodes.GOTO, LoopStart); // Jump to the start of the while loop diff --git a/src/main/java/abstractSyntaxTree/StatementExpression/AssignStatementExpression.java b/src/main/java/abstractSyntaxTree/StatementExpression/AssignStatementExpression.java index 369557f..013799e 100644 --- a/src/main/java/abstractSyntaxTree/StatementExpression/AssignStatementExpression.java +++ b/src/main/java/abstractSyntaxTree/StatementExpression/AssignStatementExpression.java @@ -29,15 +29,15 @@ public class AssignStatementExpression extends AbstractType implements IExpressi TypeCheckHelper helper = new TypeCheckHelper(); TypeCheckResult result = new TypeCheckResult(); - TypeCheckResult leftType = left.typeCheck(); - if(leftType == null){ //left expression is the identifier of a var + TypeCheckResult leftType; + + if (left instanceof LocalVarIdentifier) { leftType = new TypeCheckResult(); - if (left instanceof LocalVarIdentifier) { - LocalVarIdentifier localVarIdentifier = (LocalVarIdentifier) left; - String identifier = localVarIdentifier.getIdentifier(); - leftType.type = localVars.get(identifier); - } - // not local var + LocalVarIdentifier localVarIdentifier = (LocalVarIdentifier) left; + String identifier = localVarIdentifier.getIdentifier(); + leftType.type = localVars.get(identifier); + }else{ + leftType = left.typeCheck(); } TypeCheckResult rightType = right.typeCheck(); @@ -64,14 +64,14 @@ public class AssignStatementExpression extends AbstractType implements IExpressi left.codeGen(mv); right.codeGen(mv); - 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) { - 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); - } +// 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) { +// 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); +// } } } diff --git a/src/main/java/abstractSyntaxTree/StatementExpression/MethodCallStatementExpression.java b/src/main/java/abstractSyntaxTree/StatementExpression/MethodCallStatementExpression.java index 0540422..a78b77e 100644 --- a/src/main/java/abstractSyntaxTree/StatementExpression/MethodCallStatementExpression.java +++ b/src/main/java/abstractSyntaxTree/StatementExpression/MethodCallStatementExpression.java @@ -61,7 +61,7 @@ public class MethodCallStatementExpression extends AbstractType implements IExpr public void codeGen(MethodVisitor mv) throws Exception { //Generate Bytecode for the receiver if(classThatHasTheMethodIfNotThis != null){ - classThatHasTheMethodIfNotThis.codeGen(new ClassWriter(ClassWriter.COMPUTE_FRAMES)); + // classThatHasTheMethodIfNotThis.codeGen(new ClassWriter(ClassWriter.COMPUTE_FRAMES)); } else { mv.visitVarInsn(Opcodes.ALOAD, 0); } diff --git a/src/main/java/astGenerator/ASTGenerator.java b/src/main/java/astGenerator/ASTGenerator.java index 24e582f..90797df 100644 --- a/src/main/java/astGenerator/ASTGenerator.java +++ b/src/main/java/astGenerator/ASTGenerator.java @@ -170,7 +170,7 @@ public class ASTGenerator extends DecafBaseVisitor { @Override public Node visitAssign(DecafParser.AssignContext ctx) { - return new AssignStatementExpression(); + return new AssignStatementExpression("", null, null); } @Override From 6148b460637c83c3939af240691a9bc670fc1d2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krau=C3=9F=2C=20Josefine?= Date: Tue, 14 May 2024 15:18:18 +0200 Subject: [PATCH 5/8] parameterlist, typecheck --- .../Expression/BinaryExpression.java | 7 +++++++ .../Expression/InstVarExpression.java | 2 ++ .../Statement/IfElseStatement.java | 8 ++++---- .../Statement/IfStatement.java | 8 ++++---- .../Statement/WhileStatement.java | 10 +++++----- .../AssignStatementExpression.java | 17 ++++++++--------- .../MethodCallStatementExpression.java | 1 - .../NewStatementExpression.java | 5 ----- 8 files changed, 30 insertions(+), 28 deletions(-) diff --git a/src/main/java/abstractSyntaxTree/Expression/BinaryExpression.java b/src/main/java/abstractSyntaxTree/Expression/BinaryExpression.java index ad619f9..7e8f8a8 100644 --- a/src/main/java/abstractSyntaxTree/Expression/BinaryExpression.java +++ b/src/main/java/abstractSyntaxTree/Expression/BinaryExpression.java @@ -3,9 +3,11 @@ package abstractSyntaxTree.Expression; import TypeCheck.TypeCheckResult; import TypeCheck.TypeCheckHelper; import TypeCheck.AbstractType; +import abstractSyntaxTree.Parameter.ParameterList; import org.objectweb.asm.*; import java.beans.Expression; +import java.util.HashMap; import java.util.Objects; public class BinaryExpression extends AbstractType implements IExpression{ @@ -58,6 +60,11 @@ public class BinaryExpression extends AbstractType implements IExpression{ } + @Override + public TypeCheckResult typeCheck(HashMap>> methodContext, HashMap> typeContext, HashMap localVars) throws Exception { + return null; + } + @Override public void codeGen(MethodVisitor mv) throws Exception { // Label for the jump instruction diff --git a/src/main/java/abstractSyntaxTree/Expression/InstVarExpression.java b/src/main/java/abstractSyntaxTree/Expression/InstVarExpression.java index 6b9a261..fed4bec 100644 --- a/src/main/java/abstractSyntaxTree/Expression/InstVarExpression.java +++ b/src/main/java/abstractSyntaxTree/Expression/InstVarExpression.java @@ -24,6 +24,8 @@ public class InstVarExpression implements IExpression{ @Override public TypeCheckResult typeCheck(HashMap>> methodContext, HashMap> typeContext, HashMap localVars) throws Exception { + //todo + return null; } @Override diff --git a/src/main/java/abstractSyntaxTree/Statement/IfElseStatement.java b/src/main/java/abstractSyntaxTree/Statement/IfElseStatement.java index 650dfa1..db524e1 100644 --- a/src/main/java/abstractSyntaxTree/Statement/IfElseStatement.java +++ b/src/main/java/abstractSyntaxTree/Statement/IfElseStatement.java @@ -25,11 +25,11 @@ public class IfElseStatement extends AbstractType implements IStatement{ public TypeCheckResult typeCheck(HashMap>> methodContext, HashMap> typeContext, HashMap localVars) throws Exception { TypeCheckResult result = new TypeCheckResult(); - TypeCheckResult conditionType = condition.typeCheck(); + //TypeCheckResult conditionType = condition.typeCheck(); - if (!conditionType.equals("bool")) { - throw new IllegalArgumentException("should be boolean"); - } +// if (!conditionType.equals("bool")) { +// throw new IllegalArgumentException("should be boolean"); +// } TypeCheckResult ifStatementType = ifStatement.typeCheck(methodContext, typeContext, localVars); TypeCheckResult elseStatementType = elseStatement.typeCheck(methodContext, typeContext, localVars); diff --git a/src/main/java/abstractSyntaxTree/Statement/IfStatement.java b/src/main/java/abstractSyntaxTree/Statement/IfStatement.java index e38902e..1cc1d3a 100644 --- a/src/main/java/abstractSyntaxTree/Statement/IfStatement.java +++ b/src/main/java/abstractSyntaxTree/Statement/IfStatement.java @@ -24,11 +24,11 @@ public class IfStatement extends AbstractType implements IStatement{ public TypeCheckResult typeCheck(HashMap>> methodContext, HashMap> typeContext, HashMap localVars) throws Exception { TypeCheckResult result = new TypeCheckResult(); - TypeCheckResult conditionType = condition.typeCheck(); + //TypeCheckResult conditionType = condition.typeCheck(); - if (!conditionType.equals("bool")) { - throw new Exception("TypeCheck Exception: Condition of If-Statement should be bool."); - } +// if (!conditionType.equals("bool")) { +// throw new Exception("TypeCheck Exception: Condition of If-Statement should be bool."); +// } TypeCheckResult ifStatementType = ifStatement.typeCheck(methodContext, typeContext, localVars); result.type = ifStatementType.type; diff --git a/src/main/java/abstractSyntaxTree/Statement/WhileStatement.java b/src/main/java/abstractSyntaxTree/Statement/WhileStatement.java index 9155fb5..3132b00 100644 --- a/src/main/java/abstractSyntaxTree/Statement/WhileStatement.java +++ b/src/main/java/abstractSyntaxTree/Statement/WhileStatement.java @@ -22,11 +22,11 @@ public class WhileStatement extends AbstractType implements IStatement { public TypeCheckResult typeCheck(HashMap>> methodContext, HashMap> typeContext, HashMap localVars) throws Exception { TypeCheckResult result = new TypeCheckResult(); - TypeCheckResult conditionType = condition.typeCheck(); - - if (!conditionType.equals("bool")) { - throw new IllegalArgumentException("Expected boolean"); - } +// TypeCheckResult conditionType = condition.typeCheck(); +// +// if (!conditionType.equals("bool")) { +// throw new IllegalArgumentException("Expected boolean"); +// } TypeCheckResult statementType = statement.typeCheck(methodContext, typeContext, localVars); diff --git a/src/main/java/abstractSyntaxTree/StatementExpression/AssignStatementExpression.java b/src/main/java/abstractSyntaxTree/StatementExpression/AssignStatementExpression.java index 013799e..0600379 100644 --- a/src/main/java/abstractSyntaxTree/StatementExpression/AssignStatementExpression.java +++ b/src/main/java/abstractSyntaxTree/StatementExpression/AssignStatementExpression.java @@ -37,15 +37,15 @@ public class AssignStatementExpression extends AbstractType implements IExpressi String identifier = localVarIdentifier.getIdentifier(); leftType.type = localVars.get(identifier); }else{ - leftType = left.typeCheck(); + //leftType = left.typeCheck(); } - TypeCheckResult rightType = right.typeCheck(); - - String upperbound = helper.upperBound(leftType.type, rightType.type); - if (Objects.equals(upperbound, leftType.type)) { - result.type = leftType.type; - } - setTypeCheckResult(result); +// TypeCheckResult rightType = right.typeCheck(); +// +// String upperbound = helper.upperBound(leftType.type, rightType.type); +// if (Objects.equals(upperbound, leftType.type)) { +// result.type = leftType.type; +// } +// setTypeCheckResult(result); return result; } @@ -54,7 +54,6 @@ public class AssignStatementExpression extends AbstractType implements IExpressi } - @Override public TypeCheckResult typeCheck() throws Exception { return null; } diff --git a/src/main/java/abstractSyntaxTree/StatementExpression/MethodCallStatementExpression.java b/src/main/java/abstractSyntaxTree/StatementExpression/MethodCallStatementExpression.java index a78b77e..3fe48b6 100644 --- a/src/main/java/abstractSyntaxTree/StatementExpression/MethodCallStatementExpression.java +++ b/src/main/java/abstractSyntaxTree/StatementExpression/MethodCallStatementExpression.java @@ -25,7 +25,6 @@ public class MethodCallStatementExpression extends AbstractType implements IExpr this.arguments = arguments; } - @Override public TypeCheckResult typeCheck() throws Exception { TypeCheckResult result = new TypeCheckResult(); diff --git a/src/main/java/abstractSyntaxTree/StatementExpression/NewStatementExpression.java b/src/main/java/abstractSyntaxTree/StatementExpression/NewStatementExpression.java index da19394..7938552 100644 --- a/src/main/java/abstractSyntaxTree/StatementExpression/NewStatementExpression.java +++ b/src/main/java/abstractSyntaxTree/StatementExpression/NewStatementExpression.java @@ -11,11 +11,6 @@ import java.util.HashMap; import java.util.List; public class NewStatementExpression extends AbstractType implements IExpression, IStatement { - @Override - public TypeCheckResult typeCheck() throws Exception { - return null; - } - @Override From 3be8d9854a1f54a54c6b0c6a945eee839e9f0fbc Mon Sep 17 00:00:00 2001 From: Julian Murek Date: Tue, 14 May 2024 15:34:26 +0200 Subject: [PATCH 6/8] euqals methods overriden in "Program, RefType, MethodDecl and FieldDecl" for AST comparison. --- .../abstractSyntaxTree/Class/FieldDecl.java | 10 +++ .../abstractSyntaxTree/Class/MethodDecl.java | 17 +++- .../abstractSyntaxTree/Class/RefType.java | 12 +++ src/main/java/abstractSyntaxTree/Program.java | 10 +++ src/test/java/AST/AstComparer.java | 44 ++++++++++ src/test/java/AST/testAll.java | 28 +++++++ src/test/java/ASTs/emptyClassAST.java | 24 ++++++ .../ASTs/emptyClassWithConstructorAST.java | 34 ++++++++ src/test/java/ASTs/fourClassesAST.java | 80 +++++++++++++++++++ src/test/java/Tokens/JavaLexerTest.java | 3 - src/test/java/Tokens/TestAll.java | 34 ++++++++ 11 files changed, 289 insertions(+), 7 deletions(-) create mode 100644 src/test/java/AST/AstComparer.java create mode 100644 src/test/java/AST/testAll.java create mode 100644 src/test/java/ASTs/emptyClassAST.java create mode 100644 src/test/java/ASTs/emptyClassWithConstructorAST.java create mode 100644 src/test/java/ASTs/fourClassesAST.java create mode 100644 src/test/java/Tokens/TestAll.java diff --git a/src/main/java/abstractSyntaxTree/Class/FieldDecl.java b/src/main/java/abstractSyntaxTree/Class/FieldDecl.java index 54c0951..e5fcfe9 100644 --- a/src/main/java/abstractSyntaxTree/Class/FieldDecl.java +++ b/src/main/java/abstractSyntaxTree/Class/FieldDecl.java @@ -12,6 +12,7 @@ import org.objectweb.asm.Opcodes; import java.util.ArrayList; import java.util.HashMap; import java.util.List; +import java.util.Objects; public class FieldDecl extends AbstractType implements Node { @@ -58,4 +59,13 @@ public class FieldDecl extends AbstractType implements Node { return "L" + type + ";"; } } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + FieldDecl fieldDecl = (FieldDecl) o; + return ( Objects.equals(type, fieldDecl.type) + && Objects.equals(identifier, fieldDecl.identifier)); + } } diff --git a/src/main/java/abstractSyntaxTree/Class/MethodDecl.java b/src/main/java/abstractSyntaxTree/Class/MethodDecl.java index 2707e9f..03dc126 100644 --- a/src/main/java/abstractSyntaxTree/Class/MethodDecl.java +++ b/src/main/java/abstractSyntaxTree/Class/MethodDecl.java @@ -9,10 +9,7 @@ import abstractSyntaxTree.Statement.BlockStatement; import abstractSyntaxTree.Statement.IStatement; import org.objectweb.asm.*; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Stack; +import java.util.*; public class MethodDecl implements Node { @@ -160,4 +157,16 @@ public class MethodDecl implements Node { } return descriptor.toString(); } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + MethodDecl methodDecl = (MethodDecl) o; + return (Objects.equals(name, methodDecl.name) + && Objects.equals(parameters, methodDecl.parameters) + && Objects.equals(returnType, methodDecl.returnType) + && Objects.equals(codeBlock, methodDecl.codeBlock)); + } + } diff --git a/src/main/java/abstractSyntaxTree/Class/RefType.java b/src/main/java/abstractSyntaxTree/Class/RefType.java index c50c817..82fc95d 100644 --- a/src/main/java/abstractSyntaxTree/Class/RefType.java +++ b/src/main/java/abstractSyntaxTree/Class/RefType.java @@ -10,6 +10,7 @@ import org.objectweb.asm.Opcodes; import java.util.ArrayList; import java.util.HashMap; import java.util.List; +import java.util.Objects; public class RefType extends AbstractType implements Node { @@ -89,5 +90,16 @@ public class RefType extends AbstractType implements Node { cw.visitEnd(); } + @Override + public boolean equals(Object o) { + System.out.println("Dont forget me ;)"); + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + RefType refType = (RefType) o; + return ( Objects.equals(name, refType.name) + && Objects.equals(fieldDecls, refType.fieldDecls) + && Objects.equals(methodDecls, refType.methodDecls) + && Objects.equals(hasMain, refType.hasMain)); + } } diff --git a/src/main/java/abstractSyntaxTree/Program.java b/src/main/java/abstractSyntaxTree/Program.java index fa9397b..6ac74b4 100644 --- a/src/main/java/abstractSyntaxTree/Program.java +++ b/src/main/java/abstractSyntaxTree/Program.java @@ -102,4 +102,14 @@ public class Program implements Node { } */ } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Program program = (Program) o; + System.out.println(classes); + System.out.println(program.classes); + return (Objects.equals(classes, program.classes)); + } } \ No newline at end of file diff --git a/src/test/java/AST/AstComparer.java b/src/test/java/AST/AstComparer.java new file mode 100644 index 0000000..3ef2ce9 --- /dev/null +++ b/src/test/java/AST/AstComparer.java @@ -0,0 +1,44 @@ +package AST; + +import ASTs.emptyClassAST; +import abstractSyntaxTree.Program; +import static org.junit.Assert.assertEquals; + +import abstractSyntaxTree.Statement.BlockStatement; +import gen.DecafLexer; +import gen.DecafParser; +import org.antlr.v4.runtime.tree.ParseTree; +import org.junit.Test; +import java.nio.file.Files; +import java.nio.file.Paths; +import org.antlr.v4.runtime.*; +import abstractSyntaxTree.ASTGenerator; + +public class AstComparer { + + private static String BASE_DIR; + public AstComparer(String base_directory){ + BASE_DIR = base_directory + "/"; + } + + + public void astComparison(String sourceFilePath, Program expectedAST) throws Exception { + // Read the source file + String content = new String(Files.readAllBytes(Paths.get(BASE_DIR + sourceFilePath))); + CharStream codeCharStream = CharStreams.fromString(content); + + // Setup Lexer and Parser + DecafLexer lexer = new DecafLexer(codeCharStream); + CommonTokenStream tokens = new CommonTokenStream(lexer); + DecafParser parser = new DecafParser(tokens); + ParseTree tree = parser.program(); + + // Generate AST + ASTGenerator generator = new ASTGenerator(); + Program generatedAST = (Program) generator.visit(tree); + + // Assert that both ASTs are equal + assertEquals("The generated AST does not match the expected AST", expectedAST, generatedAST); + } + +} \ No newline at end of file diff --git a/src/test/java/AST/testAll.java b/src/test/java/AST/testAll.java new file mode 100644 index 0000000..5ec3665 --- /dev/null +++ b/src/test/java/AST/testAll.java @@ -0,0 +1,28 @@ +package AST; +import ASTs.emptyClassAST; +import abstractSyntaxTree.Program; +import org.junit.Test; + +import java.io.File; + +public class testAll { + + AstComparer astComparer; + public testAll() + { + this.astComparer = new AstComparer("src/test/resources"); + } + + @Test + public void TestAstGeneration() + { + System.out.println("Current working directory: " + new File(".").getAbsolutePath()); + Program testEmptyClassAST = emptyClassAST.getEmptyProgramm(); + + try { + astComparer.astComparison("basicClasses/emptyClass.java", testEmptyClassAST); + } catch (Exception e) { + throw new RuntimeException(e); + } + } +} diff --git a/src/test/java/ASTs/emptyClassAST.java b/src/test/java/ASTs/emptyClassAST.java new file mode 100644 index 0000000..e176d2d --- /dev/null +++ b/src/test/java/ASTs/emptyClassAST.java @@ -0,0 +1,24 @@ +package ASTs; + +import abstractSyntaxTree.*; +import abstractSyntaxTree.Class.FieldDecl; +import abstractSyntaxTree.Class.MethodDecl; +import abstractSyntaxTree.Class.RefType; + +import java.util.ArrayList; +import java.util.List; + +public class emptyClassAST { + + + public static Program getEmptyProgramm() { + List emptyFieldDeclList = new ArrayList<>(); + List emptyMethodDeclList = new ArrayList<>(); + RefType emptyClass = new RefType("emptyClass", emptyFieldDeclList, emptyMethodDeclList, false); + List classes = new ArrayList<>(); + classes.add(emptyClass); + + return (new Program(classes)); + } + +} diff --git a/src/test/java/ASTs/emptyClassWithConstructorAST.java b/src/test/java/ASTs/emptyClassWithConstructorAST.java new file mode 100644 index 0000000..8d288c2 --- /dev/null +++ b/src/test/java/ASTs/emptyClassWithConstructorAST.java @@ -0,0 +1,34 @@ +package ASTs; + +import abstractSyntaxTree.Class.FieldDecl; +import abstractSyntaxTree.Class.MethodDecl; +import abstractSyntaxTree.Class.RefType; +import abstractSyntaxTree.Parameter.Parameter; +import abstractSyntaxTree.Parameter.ParameterList; +import abstractSyntaxTree.Program; +import abstractSyntaxTree.Statement.BlockStatement; +import abstractSyntaxTree.Statement.IStatement; + +import java.util.ArrayList; +import java.util.List; + +public class emptyClassWithConstructorAST extends Program { + public emptyClassWithConstructorAST() + { + super(staticClasses()); + } + private static List staticClasses() { + List fieldDeclList = new ArrayList<>(); + + ParameterList emptyParameterList = new ParameterList(new ArrayList<>()); + List emptyIStatementList = new ArrayList<>(); + BlockStatement emptyBlockStatement = new BlockStatement(emptyIStatementList, "void"); + MethodDecl constructor = new MethodDecl("emptyClassWithConstructor", "null", "emptyClassWithConstructor", emptyParameterList, emptyBlockStatement); + List methodDeclList = new ArrayList<>(); + methodDeclList.add(constructor); + RefType emptyClass = new RefType("emptyClass", fieldDeclList, methodDeclList, false); + List classes = new ArrayList<>(); + classes.add(emptyClass); + return classes; + } +} diff --git a/src/test/java/ASTs/fourClassesAST.java b/src/test/java/ASTs/fourClassesAST.java new file mode 100644 index 0000000..5a2569c --- /dev/null +++ b/src/test/java/ASTs/fourClassesAST.java @@ -0,0 +1,80 @@ +package ASTs; + +import abstractSyntaxTree.Class.FieldDecl; +import abstractSyntaxTree.Class.MethodDecl; +import abstractSyntaxTree.Class.RefType; +import abstractSyntaxTree.Expression.IExpression; +import abstractSyntaxTree.Expression.InstVarExpression; +import abstractSyntaxTree.Parameter.Parameter; +import abstractSyntaxTree.Parameter.ParameterList; +import abstractSyntaxTree.Program; +import abstractSyntaxTree.Statement.BlockStatement; +import abstractSyntaxTree.Statement.IStatement; +import abstractSyntaxTree.Statement.ReturnStatement; +import abstractSyntaxTree.StatementExpression.AssignStatementExpression; +import abstractSyntaxTree.StatementExpression.NewStatementExpression; + +import java.util.ArrayList; +import java.util.List; + +/* +public class fourClassesAST extends Program { + + public fourClassesAST() + { + super(staticClasses()); + } + private static List staticClasses() { + + /////////// Classes /////////// + + ///////// Class: FourClasses ///////// + + /////// Fields /////// + List fieldDeclList = new ArrayList<>(); + + ParameterList emptyParameterList = new ParameterList(new ArrayList<>()); + + /////// Methods /////// + + // Main // + + List emptyIStatementList = new ArrayList<>(); + BlockStatement emptyBlockStatement = new BlockStatement(emptyIStatementList, "void"); + MethodDecl constructor = new MethodDecl("emptyClassWithConstructor", "null", "emptyClassWithConstructor", emptyParameterList, emptyBlockStatement); + + //IStatement + List fourClassesMainBlockIstatements = new ArrayList<>(); + + IExpression atntiLeft = new InstVarExpression("Test", "t"); + IExpression atntiRight = new NewStatementExpression(); + AssignStatementExpression atnti = new AssignStatementExpression(atntiLeft, "=", ); + + + ReturnStatement fcmbiReturn = new ReturnStatement(); + + fourClassesMainBlockIstatements.add(atnti); + //BlockStatement + BlockStatement fourClassesMainBlock = new BlockStatement(fourClassesMainBlockIstatements, "int"); + + //Parameter + Parameter intI = new Parameter("int", "i"); + List fourClassesMainParameterList = new ArrayList<>(); + + ParameterList fourClassesMainParameters = new ParameterList(fourClassesMainParameterList); + + MethodDecl fourClassesMain = new MethodDecl("fourClasses", "int", "main", fourClassesMainParameters, fourClassesMainBlock); + List MethodDeclList = new ArrayList<>(); + + RefType emptyClass = new RefType("emptyClass", fieldDeclList, MethodDeclList, false); + + + + + + + List classes = new ArrayList<>(); + classes.add(emptyClass); + return classes; + } +}*/ diff --git a/src/test/java/Tokens/JavaLexerTest.java b/src/test/java/Tokens/JavaLexerTest.java index 12c5ea6..f08e302 100644 --- a/src/test/java/Tokens/JavaLexerTest.java +++ b/src/test/java/Tokens/JavaLexerTest.java @@ -5,7 +5,6 @@ import org.antlr.v4.runtime.CharStream; import org.antlr.v4.runtime.CharStreams; import org.antlr.v4.runtime.CommonTokenStream; import org.antlr.v4.runtime.Token; -import org.junit.Test; import java.nio.file.Files; import java.nio.file.Paths; @@ -40,8 +39,6 @@ public class JavaLexerTest { }*/ // Compare tokens - //assertEquals("Number of tokens does not match expected", expectedTokens.size(), tokenList.size()); - for (int i = 0; i < tokenList.size(); i++) { Token token = tokenList.get(i); String tokenData = String.format("%s: \"%s\"", lexer.getVocabulary().getSymbolicName(token.getType()), token.getText()); diff --git a/src/test/java/Tokens/TestAll.java b/src/test/java/Tokens/TestAll.java new file mode 100644 index 0000000..17f4b64 --- /dev/null +++ b/src/test/java/Tokens/TestAll.java @@ -0,0 +1,34 @@ +package Tokens; + +import org.junit.Test; + +public class TestAll { + JavaLexerTest testLexer; + public TestAll(){ + testLexer = new JavaLexerTest("src/test/resources"); + } + + private static void main(String[] args){ + TestAll tester = new TestAll(); + } + + @Test + public void testEmptyClass() throws Exception { + testLexer.testTokens("basicClasses/emptyClass.java", "basicClasses/emptyClass.tokens"); + } + + @Test + public void testEmptyClassWithConstructor() throws Exception { + testLexer.testTokens("basicClasses/EmptyClassWithConstructor.java", "basicClasses/EmptyClassWithConstructor.tokens"); + } + + @Test + public void testFourClasses() throws Exception { + testLexer.testTokens("basicClasses/FourClasses.java", "basicClasses/FourClasses.tokens"); + } + + @Test + public void testPublicEmptyClass() throws Exception { + testLexer.testTokens("basicClasses/PublicEmptyClass.java", "basicClasses/PublicEmptyClass.tokens"); + } +} From 108b8f63ea4c05ca0c5d388af0c115eb64bed491 Mon Sep 17 00:00:00 2001 From: Jochen Seyfried Date: Wed, 22 May 2024 10:05:20 +0200 Subject: [PATCH 7/8] Updated CodeGen of FiledDecl and MethodDecl and Assign --- src/main/java/abstractSyntaxTree/Class/FieldDecl.java | 4 ++-- src/main/java/abstractSyntaxTree/Class/MethodDecl.java | 4 ++-- src/main/java/abstractSyntaxTree/Class/RefType.java | 2 +- .../java/abstractSyntaxTree/Statement/LocalVarDecl.java | 3 ++- .../abstractSyntaxTree/Statement/ReturnStatement.java | 4 ++-- .../StatementExpression/AssignStatementExpression.java | 9 ++++++++- 6 files changed, 17 insertions(+), 9 deletions(-) diff --git a/src/main/java/abstractSyntaxTree/Class/FieldDecl.java b/src/main/java/abstractSyntaxTree/Class/FieldDecl.java index e5fcfe9..72fa97b 100644 --- a/src/main/java/abstractSyntaxTree/Class/FieldDecl.java +++ b/src/main/java/abstractSyntaxTree/Class/FieldDecl.java @@ -41,7 +41,7 @@ public class FieldDecl extends AbstractType implements Node { } public void codeGen(ClassWriter cw) { - //TODO: Do we have fields with initial values? + //TODO: Do we have fields with initial values? --> No dont think so --> assign FieldVisitor fv = cw.visitField(Opcodes.ACC_PUBLIC, identifier, getFieldDescriptor(), null, null); fv.visitEnd(); } @@ -51,7 +51,7 @@ public class FieldDecl extends AbstractType implements Node { switch (type) { case "int": return "I"; - case "boolean": + case "bool": return "Z"; case "char": return "C"; diff --git a/src/main/java/abstractSyntaxTree/Class/MethodDecl.java b/src/main/java/abstractSyntaxTree/Class/MethodDecl.java index 03dc126..125b5c6 100644 --- a/src/main/java/abstractSyntaxTree/Class/MethodDecl.java +++ b/src/main/java/abstractSyntaxTree/Class/MethodDecl.java @@ -116,7 +116,7 @@ public class MethodDecl implements Node { for (Parameter param : parameters.parameterList) { switch (param.type) { case "int" -> descriptor.append("I"); - case "boolean" -> descriptor.append("Z"); + case "bool" -> descriptor.append("Z"); case "char" -> descriptor.append("C"); case "void" -> descriptor.append("V"); default -> { @@ -136,7 +136,7 @@ public class MethodDecl implements Node { } else { switch (returnType) { case "int" -> descriptor.append("I"); - case "boolean" -> descriptor.append("Z"); + case "bool" -> descriptor.append("Z"); case "char" -> descriptor.append("C"); case "void" -> descriptor.append("V"); default -> { diff --git a/src/main/java/abstractSyntaxTree/Class/RefType.java b/src/main/java/abstractSyntaxTree/Class/RefType.java index 82fc95d..19bc5f6 100644 --- a/src/main/java/abstractSyntaxTree/Class/RefType.java +++ b/src/main/java/abstractSyntaxTree/Class/RefType.java @@ -85,7 +85,7 @@ public class RefType extends AbstractType implements Node { } for (MethodDecl method : methodDecls) { - // method.codeGen(cw); + method.codeGen(cw, methodContext); } cw.visitEnd(); } diff --git a/src/main/java/abstractSyntaxTree/Statement/LocalVarDecl.java b/src/main/java/abstractSyntaxTree/Statement/LocalVarDecl.java index 4fd73a4..b01d899 100644 --- a/src/main/java/abstractSyntaxTree/Statement/LocalVarDecl.java +++ b/src/main/java/abstractSyntaxTree/Statement/LocalVarDecl.java @@ -4,6 +4,7 @@ import TypeCheck.TypeCheckHelper; import TypeCheck.TypeCheckResult; import abstractSyntaxTree.Parameter.ParameterList; import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; import java.util.ArrayList; import java.util.Arrays; @@ -30,6 +31,6 @@ public class LocalVarDecl implements IStatement{ @Override public void codeGen(MethodVisitor mv, HashMap localVars) throws Exception { - + localVars.put(identifier, type); } } diff --git a/src/main/java/abstractSyntaxTree/Statement/ReturnStatement.java b/src/main/java/abstractSyntaxTree/Statement/ReturnStatement.java index 358ee25..d97bc06 100644 --- a/src/main/java/abstractSyntaxTree/Statement/ReturnStatement.java +++ b/src/main/java/abstractSyntaxTree/Statement/ReturnStatement.java @@ -7,7 +7,6 @@ import abstractSyntaxTree.Parameter.ParameterList; import org.objectweb.asm.*; import java.util.HashMap; -import java.util.List; public class ReturnStatement extends AbstractType implements IStatement{ IExpression expression; @@ -39,7 +38,8 @@ public class ReturnStatement extends AbstractType implements IStatement{ if (expression != null) { expression.codeGen(mv); //Get the Type of the expression - String type = expression.typeCheck().type; + //TODO: Resolve how do we get the type of the expression + String type = expression.typeCheck(??).type; if (type.equals("int") || type.equals("bool") || type.equals("char")) { mv.visitInsn(Opcodes.IRETURN); diff --git a/src/main/java/abstractSyntaxTree/StatementExpression/AssignStatementExpression.java b/src/main/java/abstractSyntaxTree/StatementExpression/AssignStatementExpression.java index 3f289dc..7c48d8e 100644 --- a/src/main/java/abstractSyntaxTree/StatementExpression/AssignStatementExpression.java +++ b/src/main/java/abstractSyntaxTree/StatementExpression/AssignStatementExpression.java @@ -8,6 +8,7 @@ import abstractSyntaxTree.Expression.InstVarExpression; import abstractSyntaxTree.Expression.LocalVarIdentifier; import abstractSyntaxTree.Parameter.ParameterList; import abstractSyntaxTree.Statement.IStatement; +import abstractSyntaxTree.Statement.LocalVarDecl; import org.objectweb.asm.*; import java.util.HashMap; @@ -51,7 +52,13 @@ public class AssignStatementExpression extends AbstractType implements IExpressi @Override public void codeGen(MethodVisitor mv, HashMap localVars) throws Exception { - if (left instanceof VarRefExpression varRef) { + if (left instanceof LocalVarIdentifier) { + LocalVarIdentifier localVar = (LocalVarIdentifier) left; + String varName = localVar.getIdentifier(); + + //Get the index of the local variable + int varIndex = localVars.get(varName) + } From b91174eeee60a7fd911717a2cafc7af209510d6d Mon Sep 17 00:00:00 2001 From: Jochen Seyfried Date: Wed, 22 May 2024 12:49:59 +0200 Subject: [PATCH 8/8] Implemented CodeGen for Assign and MethodCall. But MethodCall is not working at the moment --- .../abstractSyntaxTree/Class/FieldDecl.java | 7 +- .../abstractSyntaxTree/Class/MethodDecl.java | 5 +- .../Expression/BinaryExpression.java | 51 +++++------ .../Expression/IExpression.java | 3 +- .../Expression/InstVarExpression.java | 38 ++++++-- .../Expression/LocalVarIdentifier.java | 41 ++++++++- .../Expression/UnaryExpression.java | 4 +- .../Statement/IStatement.java | 5 +- .../Statement/LocalVarDecl.java | 19 ++++ .../AssignStatementExpression.java | 89 +++++++++++++------ .../MethodCallStatementExpression.java | 38 +++++--- 11 files changed, 217 insertions(+), 83 deletions(-) diff --git a/src/main/java/abstractSyntaxTree/Class/FieldDecl.java b/src/main/java/abstractSyntaxTree/Class/FieldDecl.java index 72fa97b..b77814d 100644 --- a/src/main/java/abstractSyntaxTree/Class/FieldDecl.java +++ b/src/main/java/abstractSyntaxTree/Class/FieldDecl.java @@ -36,10 +36,6 @@ public class FieldDecl extends AbstractType implements Node { //write field table } - public TypeCheckResult typeCheck(HashMap>>> methodContext, HashMap> typeContext, List fieldsOrMethods) throws Exception { - return null; - } - public void codeGen(ClassWriter cw) { //TODO: Do we have fields with initial values? --> No dont think so --> assign FieldVisitor fv = cw.visitField(Opcodes.ACC_PUBLIC, identifier, getFieldDescriptor(), null, null); @@ -47,11 +43,10 @@ public class FieldDecl extends AbstractType implements Node { } private String getFieldDescriptor() { - //TODO: Maybe we have to check for arrays? switch (type) { case "int": return "I"; - case "bool": + case "boolean": return "Z"; case "char": return "C"; diff --git a/src/main/java/abstractSyntaxTree/Class/MethodDecl.java b/src/main/java/abstractSyntaxTree/Class/MethodDecl.java index 125b5c6..fc074c7 100644 --- a/src/main/java/abstractSyntaxTree/Class/MethodDecl.java +++ b/src/main/java/abstractSyntaxTree/Class/MethodDecl.java @@ -22,7 +22,8 @@ public class MethodDecl implements Node { public String returnType; public BlockStatement codeBlock; - public HashMap localVars; + //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){ this.classThatContainsMethod = classThatContainsMethod; @@ -30,7 +31,7 @@ public class MethodDecl implements Node { this.name = name; this.parameters = parameters; this.codeBlock = codeBlock; - this.localVars = new HashMap<>(); + this.localVars = new LinkedHashMap<>(); } public TypeCheckResult typeCheck(HashMap>> methodContext, HashMap> typeContext) throws Exception { diff --git a/src/main/java/abstractSyntaxTree/Expression/BinaryExpression.java b/src/main/java/abstractSyntaxTree/Expression/BinaryExpression.java index 7e8f8a8..f73af36 100644 --- a/src/main/java/abstractSyntaxTree/Expression/BinaryExpression.java +++ b/src/main/java/abstractSyntaxTree/Expression/BinaryExpression.java @@ -8,6 +8,7 @@ import org.objectweb.asm.*; import java.beans.Expression; import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.Objects; public class BinaryExpression extends AbstractType implements IExpression{ @@ -66,7 +67,7 @@ public class BinaryExpression extends AbstractType implements IExpression{ } @Override - public void codeGen(MethodVisitor mv) throws Exception { + public void codeGen(MethodVisitor mv, HashMap> typeContext, LinkedHashMap localVars) throws Exception { // Label for the jump instruction Label operationFalse = new Label(); //Operation is false Label operationTrue = new Label(); //Operation is true @@ -76,88 +77,88 @@ public class BinaryExpression extends AbstractType implements IExpression{ // Bytecode for the binary operation switch (operator) { case "&&": - left.codeGen(mv); + left.codeGen(mv, typeContext, localVars); mv.visitJumpInsn(Opcodes.IFEQ, operationFalse); // IFEQ --> "if equals to zero" (false) --> if left exp is false - right.codeGen(mv); + right.codeGen(mv, typeContext, localVars); 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); + left.codeGen(mv, typeContext, localVars); mv.visitJumpInsn(Opcodes.IFNE, operationTrue); // IFNE --> "if not equals to zero" (true) --> if left exp is true - right.codeGen(mv); + right.codeGen(mv, typeContext, localVars); 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); - right.codeGen(mv); + left.codeGen(mv, typeContext, localVars); + right.codeGen(mv, typeContext, localVars); mv.visitJumpInsn(Opcodes.IF_ICMPEQ, operationTrue); // If the two values are equal, jump to the end of the expression break; case "<": - left.codeGen(mv); - right.codeGen(mv); + left.codeGen(mv, typeContext, localVars); + right.codeGen(mv, typeContext, localVars); mv.visitJumpInsn(Opcodes.IF_ICMPLT, operationTrue); // Checks only on less than, not equal break; case ">": - left.codeGen(mv); - right.codeGen(mv); + left.codeGen(mv, typeContext, localVars); + right.codeGen(mv, typeContext, localVars); mv.visitJumpInsn(Opcodes.IF_ICMPGT, operationTrue); // Checks only on greater than, not equal break; case "<=": - left.codeGen(mv); - right.codeGen(mv); + left.codeGen(mv, typeContext, localVars); + right.codeGen(mv, typeContext, localVars); mv.visitJumpInsn(Opcodes.IF_ICMPLE, operationTrue); // Checks on less than OR equal break; case ">=": - left.codeGen(mv); - right.codeGen(mv); + left.codeGen(mv, typeContext, localVars); + right.codeGen(mv, typeContext, localVars); mv.visitJumpInsn(Opcodes.IF_ICMPGE, operationTrue); // Checks on greater than OR equal break; case "!=": - left.codeGen(mv); - right.codeGen(mv); + left.codeGen(mv, typeContext, localVars); + right.codeGen(mv, typeContext, localVars); mv.visitJumpInsn(Opcodes.IF_ICMPNE, operationTrue); // Checks on not equal break; case "+": - left.codeGen(mv); - right.codeGen(mv); + left.codeGen(mv, typeContext, localVars); + right.codeGen(mv, typeContext, localVars); mv.visitInsn(Opcodes.IADD); break; case "-": - left.codeGen(mv); - right.codeGen(mv); + left.codeGen(mv, typeContext, localVars); + right.codeGen(mv, typeContext, localVars); mv.visitInsn(Opcodes.ISUB); break; case "*": - left.codeGen(mv); - right.codeGen(mv); + left.codeGen(mv, typeContext, localVars); + right.codeGen(mv, typeContext, localVars); mv.visitInsn(Opcodes.IMUL); break; case "/": - left.codeGen(mv); - right.codeGen(mv); + left.codeGen(mv, typeContext, localVars); + right.codeGen(mv, typeContext, localVars); mv.visitInsn(Opcodes.IDIV); break; diff --git a/src/main/java/abstractSyntaxTree/Expression/IExpression.java b/src/main/java/abstractSyntaxTree/Expression/IExpression.java index 1245400..24c4ac1 100644 --- a/src/main/java/abstractSyntaxTree/Expression/IExpression.java +++ b/src/main/java/abstractSyntaxTree/Expression/IExpression.java @@ -5,6 +5,7 @@ import abstractSyntaxTree.Parameter.ParameterList; import org.objectweb.asm.MethodVisitor; import java.util.HashMap; +import java.util.LinkedHashMap; public interface IExpression { // typeCheck method @@ -12,5 +13,5 @@ public interface IExpression { TypeCheckResult typeCheck(HashMap>> methodContext, HashMap> typeContext, HashMap localVars) throws Exception; // visit method for code generation - void codeGen(MethodVisitor mv) throws Exception; + void codeGen(MethodVisitor mv, HashMap> typeContext, LinkedHashMap localVars) throws Exception; } diff --git a/src/main/java/abstractSyntaxTree/Expression/InstVarExpression.java b/src/main/java/abstractSyntaxTree/Expression/InstVarExpression.java index fed4bec..a1eee95 100644 --- a/src/main/java/abstractSyntaxTree/Expression/InstVarExpression.java +++ b/src/main/java/abstractSyntaxTree/Expression/InstVarExpression.java @@ -5,15 +5,17 @@ import abstractSyntaxTree.Class.RefType; import abstractSyntaxTree.Parameter.ParameterList; import jdk.jshell.spi.ExecutionControl; import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; import java.util.HashMap; +import java.util.LinkedHashMap; 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 - private RefType classRef; - private String fieldName; + public RefType classRef; + public String fieldName; public InstVarExpression(RefType classRef, String fieldName){ this.classRef = classRef; @@ -29,11 +31,33 @@ public class InstVarExpression implements IExpression{ } @Override - public void codeGen(MethodVisitor mv) throws Exception { - throw new ExecutionControl.NotImplementedException("CodeGen not implemented for InstVarExpression"); + // typeContext: (ClassName, (FieldName, FieldType)) + public void codeGen(MethodVisitor mv, HashMap> typeContext, LinkedHashMap localVars) throws Exception { + // Load "this" onto the stack + mv.visitVarInsn(Opcodes.ALOAD, 0); - //ALOAD the index of the var - //GETFIELD the field - //visitFieldInsn(Opcodes.GETFIELD, "class reference", "field name", type); + //Get the field information + String fieldType = typeContext.get(classRef.name).get(fieldName); + + String fieldDescriptor; + + switch (fieldType) { + case "int": + fieldDescriptor = "I"; + break; + case "boolean": + fieldDescriptor = "Z"; + break; + case "char": + fieldDescriptor = "C"; + break; + default: + //TODO: We need the fully qualified name of the class here in field type + fieldDescriptor = "L" + fieldType + ";"; + break; + } + + // Load the variable onto the stack + mv.visitFieldInsn(Opcodes.GETFIELD, classRef.name, fieldName, fieldDescriptor); } } diff --git a/src/main/java/abstractSyntaxTree/Expression/LocalVarIdentifier.java b/src/main/java/abstractSyntaxTree/Expression/LocalVarIdentifier.java index 7c1888a..0fe02a0 100644 --- a/src/main/java/abstractSyntaxTree/Expression/LocalVarIdentifier.java +++ b/src/main/java/abstractSyntaxTree/Expression/LocalVarIdentifier.java @@ -2,7 +2,10 @@ package abstractSyntaxTree.Expression; import TypeCheck.TypeCheckHelper; import TypeCheck.TypeCheckResult; -import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.*; + +import java.util.HashMap; +import java.util.LinkedHashMap; public class LocalVarIdentifier implements IExpression{ @@ -21,7 +24,41 @@ public class LocalVarIdentifier implements IExpression{ } @Override - public void codeGen(MethodVisitor mv) throws Exception { + public void codeGen(MethodVisitor mv, HashMap> typeContext, LinkedHashMap localVars) throws Exception { + // Check if the variable is in the list of local variables + String type = localVars.get(identifier); + if (type == null){ + throw new Exception("Variable " + identifier + " not declared"); + } + // Load the variable onto the stack + int index = -1; + int counter = 0; + for (String key : localVars.keySet()){ + if (key.equals(identifier)){ + index = counter; + break; + } + counter++; + } + + if (index == -1){ + throw new Exception("Variable " + identifier + " not found"); + } + + // Load the variable onto the stack + switch (type){ + case "int": + mv.visitVarInsn(Opcodes.ILOAD, index); + break; + case "bool": + mv.visitVarInsn(Opcodes.ILOAD, index); + break; + case "void": + break; + default: + mv.visitVarInsn(Opcodes.ALOAD, index); + break; + } } } diff --git a/src/main/java/abstractSyntaxTree/Expression/UnaryExpression.java b/src/main/java/abstractSyntaxTree/Expression/UnaryExpression.java index 6fb57f9..9669e84 100644 --- a/src/main/java/abstractSyntaxTree/Expression/UnaryExpression.java +++ b/src/main/java/abstractSyntaxTree/Expression/UnaryExpression.java @@ -7,6 +7,8 @@ import abstractSyntaxTree.Datatype.IDatatype; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; +import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.Objects; public class UnaryExpression extends AbstractType implements IExpression{ @@ -47,7 +49,7 @@ public class UnaryExpression extends AbstractType implements IExpression{ } @Override - public void codeGen(MethodVisitor mv) throws Exception { + public void codeGen(MethodVisitor mv, HashMap> typeContext, LinkedHashMap localVars) throws Exception { operand.codeGen(mv); diff --git a/src/main/java/abstractSyntaxTree/Statement/IStatement.java b/src/main/java/abstractSyntaxTree/Statement/IStatement.java index 2225532..1ee7271 100644 --- a/src/main/java/abstractSyntaxTree/Statement/IStatement.java +++ b/src/main/java/abstractSyntaxTree/Statement/IStatement.java @@ -6,11 +6,14 @@ import abstractSyntaxTree.Parameter.ParameterList; import org.objectweb.asm.MethodVisitor; import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.List; public interface IStatement extends Node { TypeCheckResult typeCheck(HashMap>> methodContext, HashMap> typeContext, HashMap localVars) throws Exception; - void codeGen(MethodVisitor mv, HashMap localVars) throws Exception; + void codeGen(MethodVisitor mv, LinkedHashMap localVars) throws Exception; + + void codeGen(MethodVisitor mv, LinkedHashMap localVars, HashMap> typeContext) throws Exception; } diff --git a/src/main/java/abstractSyntaxTree/Statement/LocalVarDecl.java b/src/main/java/abstractSyntaxTree/Statement/LocalVarDecl.java index b01d899..c53b3af 100644 --- a/src/main/java/abstractSyntaxTree/Statement/LocalVarDecl.java +++ b/src/main/java/abstractSyntaxTree/Statement/LocalVarDecl.java @@ -32,5 +32,24 @@ public class LocalVarDecl implements IStatement{ @Override public void codeGen(MethodVisitor mv, HashMap localVars) throws Exception { localVars.put(identifier, type); + + // Set a default value for the variable --> less problems + int index = localVars.size()-1; + + switch (type){ + case "int": + mv.visitInsn(Opcodes.ICONST_0); + mv.visitVarInsn(Opcodes.ISTORE, index); + break; + case "bool": + 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/StatementExpression/AssignStatementExpression.java b/src/main/java/abstractSyntaxTree/StatementExpression/AssignStatementExpression.java index 7c48d8e..b3c5868 100644 --- a/src/main/java/abstractSyntaxTree/StatementExpression/AssignStatementExpression.java +++ b/src/main/java/abstractSyntaxTree/StatementExpression/AssignStatementExpression.java @@ -8,16 +8,16 @@ import abstractSyntaxTree.Expression.InstVarExpression; import abstractSyntaxTree.Expression.LocalVarIdentifier; import abstractSyntaxTree.Parameter.ParameterList; import abstractSyntaxTree.Statement.IStatement; -import abstractSyntaxTree.Statement.LocalVarDecl; import org.objectweb.asm.*; import java.util.HashMap; -import java.util.Objects; +import java.util.LinkedHashMap; public class AssignStatementExpression extends AbstractType implements IExpression, IStatement { public String operator; public IExpression left; public IExpression right; + private InstVarExpression instVar; public AssignStatementExpression(String operator, IExpression leftExpression, IExpression rightExpression){ this.operator = operator; @@ -50,37 +50,70 @@ public class AssignStatementExpression extends AbstractType implements IExpressi return result; } - @Override - public void codeGen(MethodVisitor mv, HashMap localVars) throws Exception { - if (left instanceof LocalVarIdentifier) { - LocalVarIdentifier localVar = (LocalVarIdentifier) left; - String varName = localVar.getIdentifier(); - - //Get the index of the local variable - int varIndex = localVars.get(varName) - - - } - - } - public TypeCheckResult typeCheck() throws Exception { return null; } @Override - public void codeGen(MethodVisitor mv) throws Exception { - left.codeGen(mv); - right.codeGen(mv); + public void codeGen(MethodVisitor mv, HashMap> typeContext, LinkedHashMap localVars) throws Exception { + //TODO: Do we need the value on the stack after assigning it? + //TODO: WE do not differentiate between InstanceVar and FieldVar -// 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) { -// 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); -// } + // Call the codeGen on the right expression which will push the value of the right expression onto the stack + right.codeGen(mv, typeContext, localVars); + + if (left instanceof LocalVarIdentifier) { + LocalVarIdentifier localVar = (LocalVarIdentifier) left; + String varName = localVar.getIdentifier(); + + //Get the index of the local variable + int index = -1; + int counter = 0; + for (String key : localVars.keySet()){ + if (key.equals(varName)){ + index = counter; + break; + } + counter++; + } + + if (index == -1){ + throw new Exception("Variable " + varName + " not found"); + } + + String type = localVars.get(localVar.getIdentifier()); + switch (type) { + case "int": + case "bool": + mv.visitVarInsn(Opcodes.ISTORE, index); + break; + default: + mv.visitVarInsn(Opcodes.ASTORE, index); + break; + } + + } else if (left instanceof InstVarExpression){ + instVar = (InstVarExpression) left; + + // Load "this" onto the stack + mv.visitVarInsn(Opcodes.ALOAD, 0); + + String fieldType = typeContext.get(instVar.classRef.name).get(instVar.fieldName); + + String fieldDescriptor; + switch (fieldType) { + case "int": + fieldDescriptor = "I"; + break; + case "boolean": + fieldDescriptor = "Z"; + break; + default: + //TODO: We need the fully qualified name of the class here in field type + fieldDescriptor = "L" + fieldType + ";"; + break; + } + mv.visitFieldInsn(Opcodes.PUTFIELD, instVar.classRef.name, instVar.fieldName, fieldDescriptor); + } } } diff --git a/src/main/java/abstractSyntaxTree/StatementExpression/MethodCallStatementExpression.java b/src/main/java/abstractSyntaxTree/StatementExpression/MethodCallStatementExpression.java index 3fe48b6..7a8498c 100644 --- a/src/main/java/abstractSyntaxTree/StatementExpression/MethodCallStatementExpression.java +++ b/src/main/java/abstractSyntaxTree/StatementExpression/MethodCallStatementExpression.java @@ -12,6 +12,7 @@ import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.List; public class MethodCallStatementExpression extends AbstractType implements IExpression, IStatement { @@ -50,27 +51,44 @@ public class MethodCallStatementExpression extends AbstractType implements IExpr return null; } - @Override - public void codeGen(MethodVisitor mv, HashMap localVars) throws Exception { - - } //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) throws Exception { + public void codeGen(MethodVisitor mv, HashMap> typeContext, LinkedHashMap localVars) throws Exception { //Generate Bytecode for the receiver if(classThatHasTheMethodIfNotThis != null){ - // classThatHasTheMethodIfNotThis.codeGen(new ClassWriter(ClassWriter.COMPUTE_FRAMES)); + //TODO: classThatHasTheMethodIfNotThis must be an object --> instance of the class not the class itself + //classThatHasTheMethodIfNotThis.codeGen(); + + String descriptor; + List methodDecls = thisClass.methodDecls; + for (MethodDecl methodDecl : methodDecls) { + if (methodDecl.name.equals(methodName)) { + //Get the method descriptor + descriptor = methodDecl.getMethodDescriptor(methodContext); + } + } + mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, classThatHasTheMethodIfNotThis.name, methodName, descriptor, false); + } else { + // Load this onto the stack mv.visitVarInsn(Opcodes.ALOAD, 0); } for (IExpression argument : arguments) { - argument.codeGen(mv); + argument.codeGen(mv, typeContext, localVars); } - //We need the class reference and the return type of the method - //mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, thisClass.name, methodName, return type); - + // Get the method descriptor + String descriptor; + List methodDecls = thisClass.methodDecls; + for (MethodDecl methodDecl : methodDecls) { + if (methodDecl.name.equals(methodName)) { + //Get the method descriptor + descriptor = methodDecl.getMethodDescriptor(methodContext); + } + } + mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, thisClass.name, methodName, descriptor, false); } }