Merge remote-tracking branch 'origin/master'

# Conflicts:
#	src/main/java/abstractSyntaxTree/Expression/IExpression.java
This commit is contained in:
StefanZ3 2024-05-30 20:38:46 +02:00
commit 873d1b7a0a
33 changed files with 731 additions and 265 deletions

View File

@ -1,5 +1,14 @@
import abstractSyntaxTree.Class.RefType; 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.Program;
import abstractSyntaxTree.Statement.IStatement;
import abstractSyntaxTree.Statement.LocalVarDecl;
import abstractSyntaxTree.Statement.ReturnStatement;
import abstractSyntaxTree.StatementExpression.AssignStatementExpression;
import astGenerator.ASTGenerator; import astGenerator.ASTGenerator;
import gen.DecafLexer; import gen.DecafLexer;
import gen.DecafParser; import gen.DecafParser;
@ -82,6 +91,16 @@ public class Compiler {
// System.out.println(refType.name); // System.out.println(refType.name);
// } // }
abstractSyntaxTree.classes.get(1).methodDecls.get(0).codeBlock.returnType = "int";
List<IStatement> 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.typeCheck();
abstractSyntaxTree.codeGen(); abstractSyntaxTree.codeGen();

View File

@ -5,7 +5,7 @@ class Example {
} }
class Example2 { class Example2 {
int i; boolean instVarBool;
boolean j; int m(int n){return 1;}
} }

View File

@ -0,0 +1,6 @@
public class TestClass {
public static void main(String[] args){
new Example();
new Example2();
}
}

View File

@ -12,8 +12,9 @@ public class TypeCheckHelper {
if(type1Primitiv && type2Primitiv){ if(type1Primitiv && type2Primitiv){
if(Objects.equals(type1, type2)){ if(Objects.equals(type1, type2)){
result = type1; result = type1;
}else{
throw new Exception("no upper bound");
} }
throw new Exception("no upper bound");
}else if(type1Primitiv || type2Primitiv){ }else if(type1Primitiv || type2Primitiv){
throw new Exception("no upper bound"); throw new Exception("no upper bound");
}else{ }else{

View File

@ -12,8 +12,9 @@ import org.objectweb.asm.Opcodes;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Objects;
public class FieldDecl extends AbstractType implements IClass, Node { public class FieldDecl extends AbstractType implements Node {
public String type; // from parser public String type; // from parser
public String identifier; // from parser public String identifier; // from parser
@ -35,19 +36,13 @@ public class FieldDecl extends AbstractType implements IClass, Node {
//write field table //write field table
} }
public TypeCheckResult typeCheck(HashMap<String, HashMap<String, HashMap<String, List<String>>>> methodContext, HashMap<String, HashMap<String, String>> typeContext, List<MethodDecl> fieldsOrMethods) throws Exception {
return null;
}
@Override
public void codeGen(ClassWriter cw) { 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); FieldVisitor fv = cw.visitField(Opcodes.ACC_PUBLIC, identifier, getFieldDescriptor(), null, null);
fv.visitEnd(); fv.visitEnd();
} }
private String getFieldDescriptor() { private String getFieldDescriptor() {
//TODO: Maybe we have to check for arrays?
switch (type) { switch (type) {
case "int": case "int":
return "I"; return "I";
@ -59,4 +54,13 @@ public class FieldDecl extends AbstractType implements IClass, Node {
return "L" + type + ";"; 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));
}
} }

View File

@ -9,10 +9,7 @@ import abstractSyntaxTree.Statement.BlockStatement;
import abstractSyntaxTree.Statement.IStatement; import abstractSyntaxTree.Statement.IStatement;
import org.objectweb.asm.*; import org.objectweb.asm.*;
import java.util.HashMap; import java.util.*;
import java.util.List;
import java.util.Map;
import java.util.Stack;
public class MethodDecl implements Node { public class MethodDecl implements Node {
@ -25,7 +22,8 @@ public class MethodDecl implements Node {
public String returnType; public String returnType;
public BlockStatement codeBlock; public BlockStatement codeBlock;
public HashMap<String, String> localVars; //TODO: Can this be a linked hash map? --> need it to be to get the index of local variables
public LinkedHashMap<String, String> localVars;
public MethodDecl(String classThatContainsMethod, String returnType, String name, ParameterList parameters, BlockStatement codeBlock){ public MethodDecl(String classThatContainsMethod, String returnType, String name, ParameterList parameters, BlockStatement codeBlock){
this.classThatContainsMethod = classThatContainsMethod; this.classThatContainsMethod = classThatContainsMethod;
@ -33,14 +31,16 @@ public class MethodDecl implements Node {
this.name = name; this.name = name;
this.parameters = parameters; this.parameters = parameters;
this.codeBlock = codeBlock; this.codeBlock = codeBlock;
this.localVars = new HashMap<>(); this.localVars = new LinkedHashMap<>();
} }
public TypeCheckResult typeCheck(HashMap<String, HashMap<String, HashMap<String, List<String>>>> methodContext, HashMap<String, HashMap<String, String>> typeContext) throws Exception { public TypeCheckResult typeCheck(HashMap<String, HashMap<String, HashMap<String, ParameterList>>> methodContext, HashMap<String, HashMap<String, String>> typeContext) throws Exception {
// jede methode als block statement aufrufen und jede neue locale varibale in localvars schreiben // jede methode als block statement aufrufen und jede neue locale varibale in localvars schreiben
codeBlock.typeCheck(methodContext, typeContext); TypeCheckResult result = new TypeCheckResult();
return null; codeBlock.typeCheck(methodContext, typeContext, localVars);
result.type = codeBlock.returnType;
return result;
} }
@ -117,7 +117,7 @@ public class MethodDecl implements Node {
for (Parameter param : parameters.parameterList) { for (Parameter param : parameters.parameterList) {
switch (param.type) { switch (param.type) {
case "int" -> descriptor.append("I"); case "int" -> descriptor.append("I");
case "boolean" -> descriptor.append("Z"); case "bool" -> descriptor.append("Z");
case "char" -> descriptor.append("C"); case "char" -> descriptor.append("C");
case "void" -> descriptor.append("V"); case "void" -> descriptor.append("V");
default -> { default -> {
@ -137,7 +137,7 @@ public class MethodDecl implements Node {
} else { } else {
switch (returnType) { switch (returnType) {
case "int" -> descriptor.append("I"); case "int" -> descriptor.append("I");
case "boolean" -> descriptor.append("Z"); case "bool" -> descriptor.append("Z");
case "char" -> descriptor.append("C"); case "char" -> descriptor.append("C");
case "void" -> descriptor.append("V"); case "void" -> descriptor.append("V");
default -> { default -> {
@ -158,4 +158,16 @@ public class MethodDecl implements Node {
} }
return descriptor.toString(); 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));
}
} }

View File

@ -10,6 +10,7 @@ import org.objectweb.asm.Opcodes;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Objects;
public class RefType extends AbstractType implements Node { public class RefType extends AbstractType implements Node {
@ -30,7 +31,7 @@ public class RefType extends AbstractType implements Node {
this.hasMain = hasMain; this.hasMain = hasMain;
} }
public TypeCheckResult typeCheck(HashMap<String, HashMap<String, HashMap<String, List<String>>>> methodContext, public TypeCheckResult typeCheck(HashMap<String, HashMap<String, HashMap<String, ParameterList>>> methodContext,
HashMap<String, HashMap<String, String>> typeContext) throws Exception { HashMap<String, HashMap<String, String>> typeContext) throws Exception {
TypeCheckResult result = new TypeCheckResult(); TypeCheckResult result = new TypeCheckResult();
@ -73,7 +74,8 @@ public class RefType extends AbstractType implements Node {
// Method for code generation which iterates over all the field declarations // Method for code generation which iterates over all the field declarations
// and method declarations and calls their CodeGen methods // and method declarations and calls their CodeGen methods
public void codeGen(ClassWriter cw, HashMap<String, HashMap<String, HashMap<String, ParameterList>>> methodContext) throws Exception {
public void codeGen(ClassWriter cw, HashMap<String, HashMap<String, HashMap<String, ParameterList>>> methodContext) throws Exception {
cw.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC, name, null, cw.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC, name, null,
"java/lang/Object", null); "java/lang/Object", null);
@ -83,10 +85,21 @@ public class RefType extends AbstractType implements Node {
} }
for (MethodDecl method : methodDecls) { for (MethodDecl method : methodDecls) {
method.codeGen(cw, methodContext); method.codeGen(cw, methodContext);
} }
cw.visitEnd(); 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));
}
} }

View File

@ -3,9 +3,12 @@ package abstractSyntaxTree.Expression;
import TypeCheck.TypeCheckResult; import TypeCheck.TypeCheckResult;
import TypeCheck.TypeCheckHelper; import TypeCheck.TypeCheckHelper;
import TypeCheck.AbstractType; import TypeCheck.AbstractType;
import abstractSyntaxTree.Parameter.ParameterList;
import org.objectweb.asm.*; import org.objectweb.asm.*;
import java.beans.Expression; import java.beans.Expression;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Objects; import java.util.Objects;
public class BinaryExpression extends AbstractType implements IExpression{ public class BinaryExpression extends AbstractType implements IExpression{
@ -43,7 +46,7 @@ public class BinaryExpression extends AbstractType implements IExpression{
case "<=": case "<=":
case ">=": case ">=":
case "!=": case "!=":
result.type = helper.upperBound(leftType.type, rightType.type); result.type = helper.upperBound(leftType.type, rightType.type);
break; break;
case "-": case "-":
@ -65,7 +68,12 @@ public class BinaryExpression extends AbstractType implements IExpression{
@Override @Override
public void codeGen(MethodVisitor mv) throws Exception { public TypeCheckResult typeCheck(HashMap<String, HashMap<String, HashMap<String, ParameterList>>> methodContext, HashMap<String, HashMap<String, String>> typeContext, HashMap<String, String> localVars) throws Exception {
return null;
}
@Override
public void codeGen(MethodVisitor mv, HashMap<String, HashMap<String, String>> typeContext, LinkedHashMap<String, String> localVars) throws Exception {
// Label for the jump instruction // Label for the jump instruction
Label operationFalse = new Label(); //Operation is false Label operationFalse = new Label(); //Operation is false
Label operationTrue = new Label(); //Operation is true Label operationTrue = new Label(); //Operation is true
@ -75,88 +83,88 @@ public class BinaryExpression extends AbstractType implements IExpression{
// Bytecode for the binary operation // Bytecode for the binary operation
switch (operator) { switch (operator) {
case "&&": 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 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.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 mv.visitJumpInsn(Opcodes.GOTO, operationTrue); // If it reaches this point, the right exp is true
break; break;
case "||": 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 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); mv.visitJumpInsn(Opcodes.IFNE, operationTrue);
break; break;
case "==": case "==":
// Keep in mind that only primitive types are allowed in this case (at this time) // Keep in mind that only primitive types are allowed in this case (at this time)
left.codeGen(mv); left.codeGen(mv, typeContext, localVars);
right.codeGen(mv); right.codeGen(mv, typeContext, localVars);
mv.visitJumpInsn(Opcodes.IF_ICMPEQ, operationTrue); // If the two values are equal, jump to the end of the expression mv.visitJumpInsn(Opcodes.IF_ICMPEQ, operationTrue); // If the two values are equal, jump to the end of the expression
break; break;
case "<": case "<":
left.codeGen(mv); left.codeGen(mv, typeContext, localVars);
right.codeGen(mv); right.codeGen(mv, typeContext, localVars);
mv.visitJumpInsn(Opcodes.IF_ICMPLT, operationTrue); // Checks only on less than, not equal mv.visitJumpInsn(Opcodes.IF_ICMPLT, operationTrue); // Checks only on less than, not equal
break; break;
case ">": case ">":
left.codeGen(mv); left.codeGen(mv, typeContext, localVars);
right.codeGen(mv); right.codeGen(mv, typeContext, localVars);
mv.visitJumpInsn(Opcodes.IF_ICMPGT, operationTrue); // Checks only on greater than, not equal mv.visitJumpInsn(Opcodes.IF_ICMPGT, operationTrue); // Checks only on greater than, not equal
break; break;
case "<=": case "<=":
left.codeGen(mv); left.codeGen(mv, typeContext, localVars);
right.codeGen(mv); right.codeGen(mv, typeContext, localVars);
mv.visitJumpInsn(Opcodes.IF_ICMPLE, operationTrue); // Checks on less than OR equal mv.visitJumpInsn(Opcodes.IF_ICMPLE, operationTrue); // Checks on less than OR equal
break; break;
case ">=": case ">=":
left.codeGen(mv); left.codeGen(mv, typeContext, localVars);
right.codeGen(mv); right.codeGen(mv, typeContext, localVars);
mv.visitJumpInsn(Opcodes.IF_ICMPGE, operationTrue); // Checks on greater than OR equal mv.visitJumpInsn(Opcodes.IF_ICMPGE, operationTrue); // Checks on greater than OR equal
break; break;
case "!=": case "!=":
left.codeGen(mv); left.codeGen(mv, typeContext, localVars);
right.codeGen(mv); right.codeGen(mv, typeContext, localVars);
mv.visitJumpInsn(Opcodes.IF_ICMPNE, operationTrue); // Checks on not equal mv.visitJumpInsn(Opcodes.IF_ICMPNE, operationTrue); // Checks on not equal
break; break;
case "+": case "+":
left.codeGen(mv); left.codeGen(mv, typeContext, localVars);
right.codeGen(mv); right.codeGen(mv, typeContext, localVars);
mv.visitInsn(Opcodes.IADD); mv.visitInsn(Opcodes.IADD);
break; break;
case "-": case "-":
left.codeGen(mv); left.codeGen(mv, typeContext, localVars);
right.codeGen(mv); right.codeGen(mv, typeContext, localVars);
mv.visitInsn(Opcodes.ISUB); mv.visitInsn(Opcodes.ISUB);
break; break;
case "*": case "*":
left.codeGen(mv); left.codeGen(mv, typeContext, localVars);
right.codeGen(mv); right.codeGen(mv, typeContext, localVars);
mv.visitInsn(Opcodes.IMUL); mv.visitInsn(Opcodes.IMUL);
break; break;
case "/": case "/":
left.codeGen(mv); left.codeGen(mv, typeContext, localVars);
right.codeGen(mv); right.codeGen(mv, typeContext, localVars);
mv.visitInsn(Opcodes.IDIV); mv.visitInsn(Opcodes.IDIV);
break; break;
@ -173,4 +181,4 @@ public class BinaryExpression extends AbstractType implements IExpression{
mv.visitLabel(expressionEnd); mv.visitLabel(expressionEnd);
} }
} }

View File

@ -1,13 +1,17 @@
package abstractSyntaxTree.Expression; package abstractSyntaxTree.Expression;
import TypeCheck.TypeCheckResult; import TypeCheck.TypeCheckResult;
import abstractSyntaxTree.Node; import abstractSyntaxTree.Parameter.ParameterList;
import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.MethodVisitor;
public interface IExpression extends Node { import java.util.HashMap;
import java.util.LinkedHashMap;
public interface IExpression {
// typeCheck method // typeCheck method
TypeCheckResult typeCheck() throws Exception; //TypeCheckResult typeCheck() throws Exception;
TypeCheckResult typeCheck(HashMap<String, HashMap<String, HashMap<String, ParameterList>>> methodContext, HashMap<String, HashMap<String, String>> typeContext, HashMap<String, String> localVars) throws Exception;
// visit method for code generation // visit method for code generation
void codeGen(MethodVisitor mv) throws Exception; void codeGen(MethodVisitor mv, HashMap<String, HashMap<String, String>> typeContext, LinkedHashMap<String, String> localVars) throws Exception;
} }

View File

@ -2,31 +2,62 @@ package abstractSyntaxTree.Expression;
import TypeCheck.TypeCheckResult; import TypeCheck.TypeCheckResult;
import abstractSyntaxTree.Class.RefType; import abstractSyntaxTree.Class.RefType;
import abstractSyntaxTree.Parameter.ParameterList;
import jdk.jshell.spi.ExecutionControl; import jdk.jshell.spi.ExecutionControl;
import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import java.util.HashMap;
import java.util.LinkedHashMap;
public class InstVarExpression implements IExpression{ public class InstVarExpression implements IExpression{
//TODO: We have to decide upon more parameters and where they come from, for //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 // example here we need the index of the field, the class reference and the field name
private RefType classRef; public RefType classRef;
private String fieldName; public String fieldName;
/* public InstVarExpression(RefType classRef, String fieldName){ public InstVarExpression(RefType classRef, String fieldName){
this.classRef = classRef; this.classRef = classRef;
this.fieldName = fieldName; this.fieldName = fieldName;
}*/ }
@Override @Override
public TypeCheckResult typeCheck() throws Exception { public TypeCheckResult typeCheck(HashMap<String, HashMap<String, HashMap<String, ParameterList>>> methodContext, HashMap<String, HashMap<String, String>> typeContext, HashMap<String, String> localVars) throws Exception {
//todo
return null; return null;
} }
@Override @Override
public void codeGen(MethodVisitor mv) throws Exception { // typeContext: (ClassName, (FieldName, FieldType))
throw new ExecutionControl.NotImplementedException("CodeGen not implemented for InstVarExpression"); public void codeGen(MethodVisitor mv, HashMap<String, HashMap<String, String>> typeContext, LinkedHashMap<String, String> localVars) throws Exception {
// Load "this" onto the stack
mv.visitVarInsn(Opcodes.ALOAD, 0);
//ALOAD the index of the var //Get the field information
//GETFIELD the field String fieldType = typeContext.get(classRef.name).get(fieldName);
//visitFieldInsn(Opcodes.GETFIELD, "class reference", "field name", type);
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);
} }
} }

View File

@ -0,0 +1,64 @@
package abstractSyntaxTree.Expression;
import TypeCheck.TypeCheckHelper;
import TypeCheck.TypeCheckResult;
import org.objectweb.asm.*;
import java.util.HashMap;
import java.util.LinkedHashMap;
public class LocalVarIdentifier implements IExpression{
String identifier;
public LocalVarIdentifier(String identifier){
this.identifier = identifier;
}
public String getIdentifier() {
return identifier;
}
@Override
public TypeCheckResult typeCheck() throws Exception {
return null;
}
@Override
public void codeGen(MethodVisitor mv, HashMap<String, HashMap<String, String>> typeContext, LinkedHashMap<String, String> 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;
}
}
}

View File

@ -7,11 +7,17 @@ import abstractSyntaxTree.Datatype.IDatatype;
import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes; import org.objectweb.asm.Opcodes;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Objects; import java.util.Objects;
public class UnaryExpression extends AbstractType implements IExpression{ public class UnaryExpression extends AbstractType implements IExpression{
public String operator; public String operator;
public IDatatype operand; public IDatatype operand;
public UnaryExpression(String operator, IDatatype operand){
this.operator = operator;
this.operand = operand;
}
@Override @Override
public TypeCheckResult typeCheck() throws Exception { public TypeCheckResult typeCheck() throws Exception {
TypeCheckResult result = new TypeCheckResult(); TypeCheckResult result = new TypeCheckResult();
@ -29,12 +35,13 @@ public class UnaryExpression extends AbstractType implements IExpression{
} }
case "-": case "-":
case "+": case "":
case "+":{
if (Objects.equals(operandType, "int")){ if (Objects.equals(operandType, "int")){
result.type = "int"; result.type = "int";
} }
break; break;
}
} }
setTypeCheckResult(result); setTypeCheckResult(result);
@ -42,7 +49,7 @@ public class UnaryExpression extends AbstractType implements IExpression{
} }
@Override @Override
public void codeGen(MethodVisitor mv) throws Exception { public void codeGen(MethodVisitor mv, HashMap<String, HashMap<String, String>> typeContext, LinkedHashMap<String, String> localVars) throws Exception {
operand.codeGen(mv); operand.codeGen(mv);

View File

@ -1,23 +0,0 @@
package abstractSyntaxTree.Expression;
import TypeCheck.TypeCheckResult;
import org.objectweb.asm.MethodVisitor;
import java.util.Map;
public class VarRefExpression implements IExpression{
//Parameters that are needed here
private String varName;
private Map<String, Integer> localVars;
@Override
public TypeCheckResult typeCheck() throws Exception {
return null;
}
@Override
public void codeGen(MethodVisitor mv) throws Exception {
throw new Exception("CodeGen not implemented for VarRefExpression");
}
}

View File

@ -4,6 +4,7 @@ import TypeCheck.TypeCheckResult;
import abstractSyntaxTree.Class.FieldDecl; import abstractSyntaxTree.Class.FieldDecl;
import abstractSyntaxTree.Class.MethodDecl; import abstractSyntaxTree.Class.MethodDecl;
import abstractSyntaxTree.Class.RefType; import abstractSyntaxTree.Class.RefType;
import abstractSyntaxTree.Parameter.Parameter;
import abstractSyntaxTree.Parameter.ParameterList; import abstractSyntaxTree.Parameter.ParameterList;
import org.objectweb.asm.ClassWriter; import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Opcodes; import org.objectweb.asm.Opcodes;
@ -19,7 +20,7 @@ import java.util.jar.JarOutputStream;
public class Program implements Node { public class Program implements Node {
public List<RefType> classes; public List<RefType> classes;
public HashMap<String, HashMap<String, String>> typeContext; // (class, (type, identifier)) public HashMap<String, HashMap<String, String>> typeContext; // (class, (type, identifier))
public HashMap<String, HashMap<String, HashMap<String, ParameterList>>> methodContext; // (class, (returntype, (identifier, parameterList))) public HashMap<String, HashMap<String, HashMap<String, ParameterList>>> methodContext; // (class, (returntype, (identifier, parameter)))
public Program(List<RefType> classes){ public Program(List<RefType> classes){
this.classes = classes; this.classes = classes;
@ -40,11 +41,11 @@ public class Program implements Node {
typeContext.put(oneClass.name, classVars); typeContext.put(oneClass.name, classVars);
// build method context // build method context
HashMap<String, List<String>> methodIdentifierAndParameter = new HashMap<>(); HashMap<String, ParameterList> methodIdentifierAndParameter = new HashMap<>();
HashMap<String, HashMap<String, List<String >>> returnTypeAndMethod = new HashMap<>(); HashMap<String, HashMap<String, ParameterList>> returnTypeAndMethod = new HashMap<>();
for (MethodDecl methodDecl : oneClass.methodDecls){ for (MethodDecl methodDecl : oneClass.methodDecls){
methodIdentifierAndParameter.put(methodDecl.name, (List<String>) methodDecl.parameters); methodIdentifierAndParameter.put(methodDecl.name, methodDecl.parameters);
returnTypeAndMethod.put(methodDecl.returnType, methodIdentifierAndParameter); returnTypeAndMethod.put(methodDecl.returnType, methodIdentifierAndParameter);
} }
methodContext.put(oneClass.name, returnTypeAndMethod); methodContext.put(oneClass.name, returnTypeAndMethod);
@ -65,7 +66,7 @@ public class Program implements Node {
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
cw.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC, oneClass.name, null, "java/lang/Object", null); cw.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC, oneClass.name, null, "java/lang/Object", null);
oneClass.codeGen(cw, methodContext); // oneClass.codeGen(cw);
cw.visitEnd(); cw.visitEnd();
byte[] bytecode = cw.toByteArray(); byte[] bytecode = cw.toByteArray();
@ -101,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));
}
}

View File

@ -2,6 +2,8 @@ package abstractSyntaxTree.Statement;
import TypeCheck.TypeCheckResult; import TypeCheck.TypeCheckResult;
import TypeCheck.AbstractType; import TypeCheck.AbstractType;
import abstractSyntaxTree.Class.FieldDecl;
import abstractSyntaxTree.Parameter.ParameterList;
import org.objectweb.asm.*; import org.objectweb.asm.*;
import java.util.HashMap; 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 //We will need a parameter which holds the symbol table
HashMap<String, String > localVars; HashMap<String, String > localVars;
String returnType; public String returnType;
List<IStatement> statements; public List<IStatement> statements;
// do we need expression, statementexpression // do we need expression, statementexpression
public BlockStatement(List<IStatement> statements, String returnType){ public BlockStatement(List<IStatement> statements, String returnType){
@ -21,31 +23,24 @@ public class BlockStatement extends AbstractType implements IStatement{
} }
@Override @Override
public TypeCheckResult typeCheck() throws Exception { public TypeCheckResult typeCheck(HashMap<String, HashMap<String, HashMap<String, ParameterList>>> methodContext,
return null; HashMap<String, HashMap<String, String>> typeContext,
} HashMap<String, String> localVars) throws Exception {
@Override
public TypeCheckResult typeCheck(HashMap<String, HashMap<String, HashMap<String, List<String>>>> methodContext, HashMap<String, HashMap<String, String>> typeContext, HashMap<String, String> localVars) throws Exception {
return null;
}
@Override
public TypeCheckResult typeCheck(HashMap<String, HashMap<String, HashMap<String, List<String>>>> methodContext, HashMap<String, HashMap<String, String>> typeContext) throws Exception {
TypeCheckResult result = new TypeCheckResult(); TypeCheckResult result = new TypeCheckResult();
if(statements.size() == 0){ if(statements.size() == 0){
result.type = "void"; result.type = "void";
} }
TypeCheckResult blockType = new TypeCheckResult();
for (IStatement statement : statements) { for (IStatement statement : statements) {
TypeCheckResult typeOfCurrentStatement = statement.typeCheck(methodContext, typeContext, localVars); TypeCheckResult typeOfCurrentStatement = statement.typeCheck(methodContext, typeContext, localVars);
if (!typeOfCurrentStatement.equals(this.returnType) && !blockType.equals("void")) { if (!typeOfCurrentStatement.type.equals(this.returnType)) {
throw new IllegalArgumentException("Block returns type that it should not return"); 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 check if the block returns the needed return type in every case
// todo ignore unreadchable statements? // todo ignore unreadchable statements?
return result; return result;

View File

@ -2,26 +2,16 @@ package abstractSyntaxTree.Statement;
import TypeCheck.TypeCheckResult; import TypeCheck.TypeCheckResult;
import TypeCheck.AbstractType; import TypeCheck.AbstractType;
import abstractSyntaxTree.Parameter.ParameterList;
import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.MethodVisitor;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
public class EmptyStatement extends AbstractType implements IStatement{ public class EmptyStatement extends AbstractType implements IStatement{
@Override
public TypeCheckResult typeCheck() throws Exception {
TypeCheckResult result = new TypeCheckResult();
result.type = "void";
return result;
}
@Override @Override
public TypeCheckResult typeCheck(HashMap<String, HashMap<String, HashMap<String, List<String>>>> methodContext, HashMap<String, HashMap<String, String>> typeContext, HashMap<String, String> localVars) throws Exception { public TypeCheckResult typeCheck(HashMap<String, HashMap<String, HashMap<String, ParameterList>>> methodContext, HashMap<String, HashMap<String, String>> typeContext, HashMap<String, String> localVars) throws Exception {
return typeCheck(methodContext, typeContext);
}
@Override
public TypeCheckResult typeCheck(HashMap<String, HashMap<String, HashMap<String, List<String>>>> methodContext, HashMap<String, HashMap<String, String>> typeContext) throws Exception {
TypeCheckResult result = new TypeCheckResult(); TypeCheckResult result = new TypeCheckResult();
result.type = "void"; result.type = "void";
return result; return result;

View File

@ -2,22 +2,18 @@ package abstractSyntaxTree.Statement;
import TypeCheck.TypeCheckResult; import TypeCheck.TypeCheckResult;
import abstractSyntaxTree.Node; import abstractSyntaxTree.Node;
import abstractSyntaxTree.Parameter.ParameterList;
import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.MethodVisitor;
import java.util.HashMap; import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
public interface IStatement extends Node { public interface IStatement extends Node {
TypeCheckResult typeCheck(HashMap<String, HashMap<String, HashMap<String, ParameterList>>> methodContext, HashMap<String, HashMap<String, String>> typeContext, HashMap<String, String> localVars) throws Exception;
void codeGen(MethodVisitor mv, LinkedHashMap<String, String> localVars) throws Exception;
TypeCheckResult typeCheck() throws Exception; void codeGen(MethodVisitor mv, LinkedHashMap<String, String> localVars, HashMap<String, HashMap<String, String>> typeContext) throws Exception;
TypeCheckResult typeCheck(HashMap<String, HashMap<String, HashMap<String, List<String>>>> methodContext, HashMap<String, HashMap<String, String>> typeContext, HashMap<String, String> localVars) throws Exception;
TypeCheckResult typeCheck(HashMap<String, HashMap<String, HashMap<String, List<String>>>> methodContext, HashMap<String, HashMap<String, String>> typeContext) throws Exception;
void codeGen(MethodVisitor mv, HashMap<String, String> localVars) throws Exception;
} }

View File

@ -3,6 +3,7 @@ package abstractSyntaxTree.Statement;
import TypeCheck.TypeCheckResult; import TypeCheck.TypeCheckResult;
import TypeCheck.AbstractType; import TypeCheck.AbstractType;
import abstractSyntaxTree.Expression.IExpression; import abstractSyntaxTree.Expression.IExpression;
import abstractSyntaxTree.Parameter.ParameterList;
import org.objectweb.asm.*; import org.objectweb.asm.*;
import java.util.HashMap; import java.util.HashMap;
@ -19,18 +20,19 @@ public class IfElseStatement extends AbstractType implements IStatement{
this.elseStatement = elseStatement; this.elseStatement = elseStatement;
} }
@Override @Override
public TypeCheckResult typeCheck() throws Exception { public TypeCheckResult typeCheck(HashMap<String, HashMap<String, HashMap<String, ParameterList>>> methodContext, HashMap<String, HashMap<String, String>> typeContext, HashMap<String, String> localVars) throws Exception {
TypeCheckResult result = new TypeCheckResult(); TypeCheckResult result = new TypeCheckResult();
TypeCheckResult conditionType = condition.typeCheck(); //TypeCheckResult conditionType = condition.typeCheck();
if (!conditionType.equals("bool")) { // if (!conditionType.equals("bool")) {
throw new IllegalArgumentException("should be boolean"); // throw new IllegalArgumentException("should be boolean");
} // }
TypeCheckResult ifStatementType = ifStatement.typeCheck(); TypeCheckResult ifStatementType = ifStatement.typeCheck(methodContext, typeContext, localVars);
TypeCheckResult elseStatementType = elseStatement.typeCheck(); TypeCheckResult elseStatementType = elseStatement.typeCheck(methodContext, typeContext, localVars);
if (!ifStatementType.equals(elseStatementType)) { if (!ifStatementType.equals(elseStatementType)) {
throw new IllegalArgumentException("if and else have different types"); throw new IllegalArgumentException("if and else have different types");
@ -40,30 +42,22 @@ public class IfElseStatement extends AbstractType implements IStatement{
return result; return result;
} }
@Override
public TypeCheckResult typeCheck(HashMap<String, HashMap<String, HashMap<String, List<String>>>> methodContext, HashMap<String, HashMap<String, String>> typeContext, HashMap<String, String> localVars) throws Exception {
return null;
}
@Override
public TypeCheckResult typeCheck(HashMap<String, HashMap<String, HashMap<String, List<String>>>> methodContext, HashMap<String, HashMap<String, String>> typeContext) throws Exception {
return null;
}
@Override @Override
public void codeGen(MethodVisitor mv, HashMap<String, String> localVars) throws Exception { public void codeGen(MethodVisitor mv, HashMap<String, String> localVars) throws Exception {
HashMap<String, String> blockLocalVars = new HashMap<>(localVars);
Label conditionFalse = new Label(); Label conditionFalse = new Label();
Label statementEnd = new Label(); Label statementEnd = new Label();
condition.codeGen(mv); condition.codeGen(mv);
mv.visitJumpInsn(Opcodes.IFEQ, conditionFalse); //Checks if the condition is false (0) 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.visitJumpInsn(Opcodes.GOTO, statementEnd); //Jump to the end of the if-else statement
mv.visitLabel(conditionFalse); 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 mv.visitLabel(statementEnd); //End of the if-else statement

View File

@ -3,6 +3,7 @@ package abstractSyntaxTree.Statement;
import TypeCheck.TypeCheckResult; import TypeCheck.TypeCheckResult;
import TypeCheck.AbstractType; import TypeCheck.AbstractType;
import abstractSyntaxTree.Expression.IExpression; import abstractSyntaxTree.Expression.IExpression;
import abstractSyntaxTree.Parameter.ParameterList;
import org.objectweb.asm.*; import org.objectweb.asm.*;
import java.util.HashMap; import java.util.HashMap;
@ -18,40 +19,33 @@ public class IfStatement extends AbstractType implements IStatement{
this.condition = condition; this.condition = condition;
this.ifStatement = ifStatement; this.ifStatement = ifStatement;
} }
@Override @Override
public TypeCheckResult typeCheck() throws Exception { public TypeCheckResult typeCheck(HashMap<String, HashMap<String, HashMap<String, ParameterList>>> methodContext, HashMap<String, HashMap<String, String>> typeContext, HashMap<String, String> localVars) throws Exception {
TypeCheckResult result = new TypeCheckResult(); TypeCheckResult result = new TypeCheckResult();
TypeCheckResult conditionType = condition.typeCheck(); //TypeCheckResult conditionType = condition.typeCheck();
if (!conditionType.equals("bool")) { // if (!conditionType.equals("bool")) {
throw new Exception("TypeCheck Exception: Condition of If-Statement should be bool."); // 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; result.type = ifStatementType.type;
return result; return result;
} }
@Override
public TypeCheckResult typeCheck(HashMap<String, HashMap<String, HashMap<String, List<String>>>> methodContext, HashMap<String, HashMap<String, String>> typeContext, HashMap<String, String> localVars) throws Exception {
return null;
}
@Override
public TypeCheckResult typeCheck(HashMap<String, HashMap<String, HashMap<String, List<String>>>> methodContext, HashMap<String, HashMap<String, String>> typeContext) throws Exception {
return null;
}
@Override @Override
public void codeGen(MethodVisitor mv, HashMap<String, String> localVars) throws Exception { public void codeGen(MethodVisitor mv, HashMap<String, String> localVars) throws Exception {
HashMap<String, String> blockLocalVars = new HashMap<>(localVars);
Label conditionFalse = new Label(); Label conditionFalse = new Label();
condition.codeGen(mv); condition.codeGen(mv);
mv.visitJumpInsn(Opcodes.IFEQ, conditionFalse); //Checks if the condition is false (0) 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 mv.visitLabel(conditionFalse); // If the condition is false, the Statements in the ifBlock will not be executed
} }

View File

@ -0,0 +1,55 @@
package abstractSyntaxTree.Statement;
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;
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<String, HashMap<String, HashMap<String, ParameterList>>> methodContext, HashMap<String, HashMap<String, String>> typeContext, HashMap<String, String> 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<String, String> 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);
}
}
}

View File

@ -3,10 +3,10 @@ package abstractSyntaxTree.Statement;
import TypeCheck.TypeCheckResult; import TypeCheck.TypeCheckResult;
import TypeCheck.AbstractType; import TypeCheck.AbstractType;
import abstractSyntaxTree.Expression.IExpression; import abstractSyntaxTree.Expression.IExpression;
import abstractSyntaxTree.Parameter.ParameterList;
import org.objectweb.asm.*; import org.objectweb.asm.*;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
public class ReturnStatement extends AbstractType implements IStatement{ public class ReturnStatement extends AbstractType implements IStatement{
IExpression expression; IExpression expression;
@ -16,7 +16,7 @@ public class ReturnStatement extends AbstractType implements IStatement{
} }
@Override @Override
public TypeCheckResult typeCheck() throws Exception { public TypeCheckResult typeCheck(HashMap<String, HashMap<String, HashMap<String, ParameterList>>> methodContext, HashMap<String, HashMap<String, String>> typeContext, HashMap<String, String> localVars) throws Exception {
TypeCheckResult result = new TypeCheckResult(); TypeCheckResult result = new TypeCheckResult();
if (expression == null) { if (expression == null) {
@ -29,17 +29,6 @@ public class ReturnStatement extends AbstractType implements IStatement{
return result; return result;
} }
@Override
public TypeCheckResult typeCheck(HashMap<String, HashMap<String, HashMap<String, List<String>>>> methodContext, HashMap<String, HashMap<String, String>> typeContext, HashMap<String, String> localVars) throws Exception {
return null;
}
@Override
public TypeCheckResult typeCheck(HashMap<String, HashMap<String, HashMap<String, List<String>>>> methodContext, HashMap<String, HashMap<String, String>> typeContext) throws Exception {
return null;
}
//TODO: We do not differentiate between primitive types and reference types //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 // 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 // At this point in time we can either return reference types or have an error message
@ -49,7 +38,8 @@ public class ReturnStatement extends AbstractType implements IStatement{
if (expression != null) { if (expression != null) {
expression.codeGen(mv); expression.codeGen(mv);
//Get the Type of the expression //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")) { if (type.equals("int") || type.equals("bool") || type.equals("char")) {
mv.visitInsn(Opcodes.IRETURN); mv.visitInsn(Opcodes.IRETURN);

View File

@ -3,6 +3,7 @@ package abstractSyntaxTree.Statement;
import TypeCheck.TypeCheckResult; import TypeCheck.TypeCheckResult;
import TypeCheck.AbstractType; import TypeCheck.AbstractType;
import abstractSyntaxTree.Expression.IExpression; import abstractSyntaxTree.Expression.IExpression;
import abstractSyntaxTree.Parameter.ParameterList;
import org.objectweb.asm.*; import org.objectweb.asm.*;
import java.util.HashMap; import java.util.HashMap;
@ -18,33 +19,26 @@ public class WhileStatement extends AbstractType implements IStatement {
} }
@Override @Override
public TypeCheckResult typeCheck() throws Exception { public TypeCheckResult typeCheck(HashMap<String, HashMap<String, HashMap<String, ParameterList>>> methodContext, HashMap<String, HashMap<String, String>> typeContext, HashMap<String, String> localVars) throws Exception {
TypeCheckResult result = new TypeCheckResult(); TypeCheckResult result = new TypeCheckResult();
TypeCheckResult conditionType = condition.typeCheck(); // TypeCheckResult conditionType = condition.typeCheck();
//
// if (!conditionType.equals("bool")) {
// throw new IllegalArgumentException("Expected boolean");
// }
if (!conditionType.equals("bool")) { TypeCheckResult statementType = statement.typeCheck(methodContext, typeContext, localVars);
throw new IllegalArgumentException("Expected boolean");
}
TypeCheckResult statementType = statement.typeCheck();
result.type = statementType.type; result.type = statementType.type;
return result; return result;
} }
@Override
public TypeCheckResult typeCheck(HashMap<String, HashMap<String, HashMap<String, List<String>>>> methodContext, HashMap<String, HashMap<String, String>> typeContext, HashMap<String, String> localVars) throws Exception {
return null;
}
@Override
public TypeCheckResult typeCheck(HashMap<String, HashMap<String, HashMap<String, List<String>>>> methodContext, HashMap<String, HashMap<String, String>> typeContext) throws Exception {
return null;
}
@Override @Override
public void codeGen(MethodVisitor mv, HashMap<String, String> localVars) throws Exception { public void codeGen(MethodVisitor mv, HashMap<String, String> localVars) throws Exception {
HashMap<String, String> blockLocalVars = new HashMap<>(localVars);
Label conditionFalse = new Label(); Label conditionFalse = new Label();
Label LoopStart = new Label(); Label LoopStart = new Label();
@ -53,7 +47,8 @@ public class WhileStatement extends AbstractType implements IStatement {
condition.codeGen(mv); condition.codeGen(mv);
mv.visitJumpInsn(Opcodes.IFEQ, conditionFalse); // Checks if the condition is false (0) mv.visitJumpInsn(Opcodes.IFEQ, conditionFalse); // Checks if the condition is false (0)
statement.codeGen(mv); statement.codeGen(mv, blockLocalVars);
//statement.codeGen(mv);
//TODO: If the block ends with a return statement, we might have to pop it from the stack //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 // So the next iteration starts with a clean stack
mv.visitJumpInsn(Opcodes.GOTO, LoopStart); // Jump to the start of the while loop mv.visitJumpInsn(Opcodes.GOTO, LoopStart); // Jump to the start of the while loop

View File

@ -5,63 +5,115 @@ import TypeCheck.TypeCheckHelper;
import TypeCheck.TypeCheckResult; import TypeCheck.TypeCheckResult;
import abstractSyntaxTree.Expression.IExpression; import abstractSyntaxTree.Expression.IExpression;
import abstractSyntaxTree.Expression.InstVarExpression; import abstractSyntaxTree.Expression.InstVarExpression;
import abstractSyntaxTree.Expression.VarRefExpression; import abstractSyntaxTree.Expression.LocalVarIdentifier;
import abstractSyntaxTree.Parameter.ParameterList;
import abstractSyntaxTree.Statement.IStatement; import abstractSyntaxTree.Statement.IStatement;
import org.objectweb.asm.*; import org.objectweb.asm.*;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.LinkedHashMap;
import java.util.Objects;
public class AssignStatementExpression extends AbstractType implements IExpression, IStatement { public class AssignStatementExpression extends AbstractType implements IExpression, IStatement {
public String operator; public String operator;
public IExpression left; public IExpression left;
public IExpression right; public IExpression right;
private InstVarExpression instVar;
public AssignStatementExpression(String operator, IExpression leftExpression, IExpression rightExpression){
this.operator = operator;
this.left = leftExpression;
this.right = rightExpression;
}
@Override @Override
public TypeCheckResult typeCheck() throws Exception { public TypeCheckResult typeCheck(HashMap<String, HashMap<String, HashMap<String, ParameterList>>> methodContext, HashMap<String, HashMap<String, String>> typeContext, HashMap<String, String> localVars) throws Exception {
TypeCheckHelper helper = new TypeCheckHelper(); TypeCheckHelper helper = new TypeCheckHelper();
TypeCheckResult result = new TypeCheckResult(); TypeCheckResult result = new TypeCheckResult();
TypeCheckResult leftType = left.typeCheck(); TypeCheckResult leftType;
TypeCheckResult rightType = right.typeCheck();
String upperbound = helper.upperBound(leftType.type, rightType.type); if (left instanceof LocalVarIdentifier) {
if (Objects.equals(upperbound, leftType.type)) { leftType = new TypeCheckResult();
result.type = leftType.type; LocalVarIdentifier localVarIdentifier = (LocalVarIdentifier) left;
String identifier = localVarIdentifier.getIdentifier();
leftType.type = localVars.get(identifier);
}else{
//leftType = left.typeCheck();
} }
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; return result;
} }
@Override public TypeCheckResult typeCheck() throws Exception {
public TypeCheckResult typeCheck(HashMap<String, HashMap<String, HashMap<String, List<String>>>> methodContext, HashMap<String, HashMap<String, String>> typeContext, HashMap<String, String> localVars) throws Exception {
return null; return null;
} }
@Override @Override
public TypeCheckResult typeCheck(HashMap<String, HashMap<String, HashMap<String, List<String>>>> methodContext, HashMap<String, HashMap<String, String>> typeContext) throws Exception { public void codeGen(MethodVisitor mv, HashMap<String, HashMap<String, String>> typeContext, LinkedHashMap<String, String> localVars) throws Exception {
return null; //TODO: Do we need the value on the stack after assigning it?
} //TODO: WE do not differentiate between InstanceVar and FieldVar
@Override // Call the codeGen on the right expression which will push the value of the right expression onto the stack
public void codeGen(MethodVisitor mv, HashMap<String, String> localVars) throws Exception { right.codeGen(mv, typeContext, localVars);
} if (left instanceof LocalVarIdentifier) {
LocalVarIdentifier localVar = (LocalVarIdentifier) left;
String varName = localVar.getIdentifier();
@Override //Get the index of the local variable
public void codeGen(MethodVisitor mv) throws Exception { int index = -1;
left.codeGen(mv); int counter = 0;
right.codeGen(mv); for (String key : localVars.keySet()){
if (key.equals(varName)){
index = counter;
break;
}
counter++;
}
if (index == -1){
throw new Exception("Variable " + varName + " not found");
}
if (left instanceof VarRefExpression varRef) { String type = localVars.get(localVar.getIdentifier());
//TODO: Implement the handling of a variable reference --> I need a list of local variables switch (type) {
// for that to determine if the variable is a local or field variable case "int":
} else if (left instanceof InstVarExpression instVar) { case "bool":
mv.visitInsn(Opcodes.DUP_X1); mv.visitVarInsn(Opcodes.ISTORE, index);
break;
default:
mv.visitVarInsn(Opcodes.ASTORE, index);
break;
}
} else if (left instanceof InstVarExpression){
instVar = (InstVarExpression) left;
// We now again need the owner (class reference), name (of the Field in the owner) and type of the field // Load "this" onto the stack
//mv.visitFieldInsn(Opcodes.PUTFIELD, instVar.className, instVar.varName, instVar.type); 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);
} }
} }
} }

View File

@ -5,12 +5,14 @@ import TypeCheck.TypeCheckResult;
import abstractSyntaxTree.Class.MethodDecl; import abstractSyntaxTree.Class.MethodDecl;
import abstractSyntaxTree.Class.RefType; import abstractSyntaxTree.Class.RefType;
import abstractSyntaxTree.Expression.IExpression; import abstractSyntaxTree.Expression.IExpression;
import abstractSyntaxTree.Parameter.ParameterList;
import abstractSyntaxTree.Statement.IStatement; import abstractSyntaxTree.Statement.IStatement;
import org.objectweb.asm.ClassWriter; import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes; import org.objectweb.asm.Opcodes;
import java.util.HashMap; import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
public class MethodCallStatementExpression extends AbstractType implements IExpression, IStatement { public class MethodCallStatementExpression extends AbstractType implements IExpression, IStatement {
@ -24,7 +26,6 @@ public class MethodCallStatementExpression extends AbstractType implements IExpr
this.arguments = arguments; this.arguments = arguments;
} }
@Override
public TypeCheckResult typeCheck() throws Exception { public TypeCheckResult typeCheck() throws Exception {
TypeCheckResult result = new TypeCheckResult(); TypeCheckResult result = new TypeCheckResult();
@ -44,37 +45,50 @@ public class MethodCallStatementExpression extends AbstractType implements IExpr
return result; return result;
} }
@Override @Override
public TypeCheckResult typeCheck(HashMap<String, HashMap<String, HashMap<String, List<String>>>> methodContext, HashMap<String, HashMap<String, String>> typeContext, HashMap<String, String> localVars) throws Exception { public TypeCheckResult typeCheck(HashMap<String, HashMap<String, HashMap<String, ParameterList>>> methodContext, HashMap<String, HashMap<String, String>> typeContext, HashMap<String, String> localVars) throws Exception {
return null; return null;
} }
@Override
public TypeCheckResult typeCheck(HashMap<String, HashMap<String, HashMap<String, List<String>>>> methodContext, HashMap<String, HashMap<String, String>> typeContext) throws Exception {
return null;
}
@Override
public void codeGen(MethodVisitor mv, HashMap<String, String> localVars) throws Exception {
}
//Errors occur due to the change in parameter in the RefType class //Errors occur due to the change in parameter in the RefType class
// I need the methodContext here to get the method descriptor
@Override @Override
public void codeGen(MethodVisitor mv) throws Exception { public void codeGen(MethodVisitor mv, HashMap<String, HashMap<String, String>> typeContext, LinkedHashMap<String, String> localVars) throws Exception {
//Generate Bytecode for the receiver //Generate Bytecode for the receiver
if(classThatHasTheMethodIfNotThis != null){ 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<MethodDecl> 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 { } else {
// Load this onto the stack
mv.visitVarInsn(Opcodes.ALOAD, 0); mv.visitVarInsn(Opcodes.ALOAD, 0);
} }
for (IExpression argument : arguments) { for (IExpression argument : arguments) {
argument.codeGen(mv); argument.codeGen(mv, typeContext, localVars);
} }
//We need the class reference and the return type of the method // Get the method descriptor
//mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, thisClass.name, methodName, return type); String descriptor;
List<MethodDecl> 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);
} }
} }

View File

@ -3,6 +3,7 @@ package abstractSyntaxTree.StatementExpression;
import TypeCheck.AbstractType; import TypeCheck.AbstractType;
import TypeCheck.TypeCheckResult; import TypeCheck.TypeCheckResult;
import abstractSyntaxTree.Expression.IExpression; import abstractSyntaxTree.Expression.IExpression;
import abstractSyntaxTree.Parameter.ParameterList;
import abstractSyntaxTree.Statement.IStatement; import abstractSyntaxTree.Statement.IStatement;
import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.MethodVisitor;
@ -10,18 +11,10 @@ import java.util.HashMap;
import java.util.List; import java.util.List;
public class NewStatementExpression extends AbstractType implements IExpression, IStatement { public class NewStatementExpression extends AbstractType implements IExpression, IStatement {
@Override
public TypeCheckResult typeCheck() throws Exception {
return null;
}
@Override @Override
public TypeCheckResult typeCheck(HashMap<String, HashMap<String, HashMap<String, List<String>>>> methodContext, HashMap<String, HashMap<String, String>> typeContext, HashMap<String, String> localVars) throws Exception { public TypeCheckResult typeCheck(HashMap<String, HashMap<String, HashMap<String, ParameterList>>> methodContext, HashMap<String, HashMap<String, String>> typeContext, HashMap<String, String> localVars) throws Exception {
return null;
}
@Override
public TypeCheckResult typeCheck(HashMap<String, HashMap<String, HashMap<String, List<String>>>> methodContext, HashMap<String, HashMap<String, String>> typeContext) throws Exception {
return null; return null;
} }

View File

@ -174,7 +174,7 @@ public class ASTGenerator extends DecafBaseVisitor<Node> {
@Override @Override
public Node visitAssign(DecafParser.AssignContext ctx) { public Node visitAssign(DecafParser.AssignContext ctx) {
return new AssignStatementExpression(); return new AssignStatementExpression("", null, null);
} }
@Override @Override

View File

@ -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);
}
}

View File

@ -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);
}
}
}

View File

@ -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<FieldDecl> emptyFieldDeclList = new ArrayList<>();
List<MethodDecl> emptyMethodDeclList = new ArrayList<>();
RefType emptyClass = new RefType("emptyClass", emptyFieldDeclList, emptyMethodDeclList, false);
List<RefType> classes = new ArrayList<>();
classes.add(emptyClass);
return (new Program(classes));
}
}

View File

@ -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<RefType> staticClasses() {
List<FieldDecl> fieldDeclList = new ArrayList<>();
ParameterList emptyParameterList = new ParameterList(new ArrayList<>());
List<IStatement> emptyIStatementList = new ArrayList<>();
BlockStatement emptyBlockStatement = new BlockStatement(emptyIStatementList, "void");
MethodDecl constructor = new MethodDecl("emptyClassWithConstructor", "null", "emptyClassWithConstructor", emptyParameterList, emptyBlockStatement);
List<MethodDecl> methodDeclList = new ArrayList<>();
methodDeclList.add(constructor);
RefType emptyClass = new RefType("emptyClass", fieldDeclList, methodDeclList, false);
List<RefType> classes = new ArrayList<>();
classes.add(emptyClass);
return classes;
}
}

View File

@ -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<RefType> staticClasses() {
/////////// Classes ///////////
///////// Class: FourClasses /////////
/////// Fields ///////
List<FieldDecl> fieldDeclList = new ArrayList<>();
ParameterList emptyParameterList = new ParameterList(new ArrayList<>());
/////// Methods ///////
// Main //
List<IStatement> emptyIStatementList = new ArrayList<>();
BlockStatement emptyBlockStatement = new BlockStatement(emptyIStatementList, "void");
MethodDecl constructor = new MethodDecl("emptyClassWithConstructor", "null", "emptyClassWithConstructor", emptyParameterList, emptyBlockStatement);
//IStatement
List<IStatement> 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<Parameter> fourClassesMainParameterList = new ArrayList<>();
ParameterList fourClassesMainParameters = new ParameterList(fourClassesMainParameterList);
MethodDecl fourClassesMain = new MethodDecl("fourClasses", "int", "main", fourClassesMainParameters, fourClassesMainBlock);
List<MethodDecl> MethodDeclList = new ArrayList<>();
RefType emptyClass = new RefType("emptyClass", fieldDeclList, MethodDeclList, false);
List<RefType> classes = new ArrayList<>();
classes.add(emptyClass);
return classes;
}
}*/

View File

@ -5,7 +5,6 @@ import org.antlr.v4.runtime.CharStream;
import org.antlr.v4.runtime.CharStreams; import org.antlr.v4.runtime.CharStreams;
import org.antlr.v4.runtime.CommonTokenStream; import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.Token; import org.antlr.v4.runtime.Token;
import org.junit.Test;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Paths; import java.nio.file.Paths;
@ -40,8 +39,6 @@ public class JavaLexerTest {
}*/ }*/
// Compare tokens // Compare tokens
//assertEquals("Number of tokens does not match expected", expectedTokens.size(), tokenList.size());
for (int i = 0; i < tokenList.size(); i++) { for (int i = 0; i < tokenList.size(); i++) {
Token token = tokenList.get(i); Token token = tokenList.get(i);
String tokenData = String.format("%s: \"%s\"", lexer.getVocabulary().getSymbolicName(token.getType()), token.getText()); String tokenData = String.format("%s: \"%s\"", lexer.getVocabulary().getSymbolicName(token.getType()), token.getText());

View File

@ -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");
}
}