diff --git a/src/main/java/de/maishai/Compiler.java b/src/main/java/de/maishai/Compiler.java index 1f1ebeb..08a70a1 100644 --- a/src/main/java/de/maishai/Compiler.java +++ b/src/main/java/de/maishai/Compiler.java @@ -99,7 +99,8 @@ public class Compiler { public static void main(String[] args) { generateByteCodeFileFromFile(List.of("src/main/resources/JavaTestfiles/ClassWithConstructor.java", - "src/main/resources/JavaTestfiles/ClassWithConstructorAndMethodCall.java"), - List.of("ClassWithConstructor","ClassWithConstructorAndMethodCall")); + "src/main/resources/JavaTestfiles/ClassWithConstructorAndMethodCall.java", + "src/main/resources/JavaTestfiles/ComplexClass.java"), + List.of("ClassWithConstructor","ClassWithConstructorAndMethodCall","ComplexClass")); } } diff --git a/src/main/java/de/maishai/ExpressionGenerator.java b/src/main/java/de/maishai/ExpressionGenerator.java index 7cbee59..20203cf 100644 --- a/src/main/java/de/maishai/ExpressionGenerator.java +++ b/src/main/java/de/maishai/ExpressionGenerator.java @@ -130,7 +130,7 @@ public class ExpressionGenerator extends DecafBaseVisitor { DecafParser.RecipientContext ctx = ctxList.get(lastElement); ctxList.remove(lastElement); if (ctx.id() != null) { - return new FieldVarAccess(false, generateRecursiveOwnerChain(ctxList, recipient), ctx.id().IDENTIFIER().getText()); + return new FieldVarAccess(true, generateRecursiveOwnerChain(ctxList, recipient), ctx.id().IDENTIFIER().getText()); } if (ctx.methName() != null) { List args = new ArrayList<>(); diff --git a/src/main/java/de/maishai/typedast/ClassContext.java b/src/main/java/de/maishai/typedast/ClassContext.java index 50e100c..23cbaa8 100644 --- a/src/main/java/de/maishai/typedast/ClassContext.java +++ b/src/main/java/de/maishai/typedast/ClassContext.java @@ -6,11 +6,13 @@ import org.objectweb.asm.ClassWriter; @Data public class ClassContext { - private Type name; + private String name; + private Type type; private ClassWriter cw; public ClassContext(String name, ClassWriter cw) { - this.name = Type.REFERENCE(name); + this.name = name; + type = Type.REFERENCE(name); this.cw = cw; } } diff --git a/src/main/java/de/maishai/typedast/CodeGenUtils.java b/src/main/java/de/maishai/typedast/CodeGenUtils.java index 738241c..dc5ed5f 100644 --- a/src/main/java/de/maishai/typedast/CodeGenUtils.java +++ b/src/main/java/de/maishai/typedast/CodeGenUtils.java @@ -8,14 +8,14 @@ import java.util.List; public class CodeGenUtils { - public static String generateDescriptor(List arguments, Type returnType) { + public static String generateDescriptor(List argTypes, Type returnType) { if (returnType == null) { returnType = Type.VOID; } StringBuilder builder = new StringBuilder(); builder.append('('); - arguments.forEach(type -> builder.append(type.getType().getDescriptor())); + argTypes.forEach(type -> builder.append(type.getDescriptor())); builder.append(')'); builder.append(returnType.getDescriptor()); return builder.toString(); diff --git a/src/main/java/de/maishai/typedast/Help/TypedExpressionHelp.java b/src/main/java/de/maishai/typedast/Help/TypedExpressionHelp.java index bbd8072..2cef079 100644 --- a/src/main/java/de/maishai/typedast/Help/TypedExpressionHelp.java +++ b/src/main/java/de/maishai/typedast/Help/TypedExpressionHelp.java @@ -34,7 +34,7 @@ public class TypedExpressionHelp { } else if (expression instanceof MethodCall methodCall) { TypedMethodCall typedMethodCall = new TypedMethodCall( typedProgram, methodCall); - typedMethodCall.typeCheck( typedProgram); + typedMethodCall.typeCheck(typedProgram); return typedMethodCall; } else if (expression instanceof New newStmt) { diff --git a/src/main/java/de/maishai/typedast/MethodContext.java b/src/main/java/de/maishai/typedast/MethodContext.java index b3b0832..f252656 100644 --- a/src/main/java/de/maishai/typedast/MethodContext.java +++ b/src/main/java/de/maishai/typedast/MethodContext.java @@ -7,11 +7,12 @@ import org.objectweb.asm.Opcodes; import java.util.HashMap; import java.util.Map; +import java.util.Optional; import java.util.Stack; @Getter public class MethodContext { - private record LocalVariable(String name, int index, Type type) { + public record LocalVariable(String name, int index, Type type) { } private Label startLabel; @@ -28,7 +29,7 @@ public class MethodContext { endLabel = new Label(); this.mv = mv; this.classContext = classContext; - registerVariable("this", classContext.getName()); + registerVariable("this", classContext.getType()); mv.visitCode(); mv.visitLabel(startLabel); } @@ -39,12 +40,9 @@ public class MethodContext { variableIndex.put(name, new LocalVariable(name, index, type)); } - public int getVariableIndex(String name) { - int index = variableIndex.get(name).index; - if (index == -1) { - throw new RuntimeException("Variable not declared"); - } - return index; + public Optional getLocalVar(String name) { + LocalVariable index = variableIndex.get(name); + return Optional.ofNullable(index); } public void pushStack(String varName) { @@ -58,6 +56,22 @@ public class MethodContext { } else { mv.visitVarInsn(Opcodes.ILOAD, localVariable.index); } + System.out.println("Pushed " + variableIndex.get(varName) + " to stack"); + } + + public void pushAnonToStack() { + stack.push(localVarIndex); + if (stack.size() > maxStack) { + maxStack = stack.size(); + } + System.out.println("Pushed anon to stack"); + } + + public void pushInstantToStack () { + stack.push(localVarIndex); + if (stack.size() > maxStack) { + maxStack = stack.size(); + } } public void popStack() { @@ -66,6 +80,7 @@ public class MethodContext { public void wrapUp() { mv.visitLabel(endLabel); + System.out.println("maxStack: " + maxStack + " localVarIndex: " + localVarIndex); mv.visitMaxs(maxStack, localVarIndex); mv.visitEnd(); } diff --git a/src/main/java/de/maishai/typedast/typedclass/TypedAssignment.java b/src/main/java/de/maishai/typedast/typedclass/TypedAssignment.java index 556627e..91b92ea 100644 --- a/src/main/java/de/maishai/typedast/typedclass/TypedAssignment.java +++ b/src/main/java/de/maishai/typedast/typedclass/TypedAssignment.java @@ -25,31 +25,13 @@ public class TypedAssignment implements TypedStatement { public void convertToTypedAssignment(TypedProgram typedProgram, Assignment untyped) { value = convertExpression(typedProgram, untyped.value()); location = new TypedFieldVarAccess(typedProgram, untyped.location()); + location.typeCheck(typedProgram); } @Override public Type typeCheck(TypedProgram typedProgram) { - Type typeLeft = null; - - if (typedProgram.getCurrentClass().isThereField(location.getName())) { - typeLeft = typedProgram.getCurrentClass().getFieldType(location.getName()); - } else { - if (typedProgram.getCurrentClass().isCurrentMethodPresent() && !typedProgram.getCurrentClass().isCurrentConstructorPresent()) { - if (typedProgram.getCurrentClass().getCurrentMethod().isLocalVariableInMethod(location.getName())) { - typeLeft = typedProgram.getCurrentClass().getCurrentMethod().getLocalVariableType(location.getName()); - } else { - throw new RuntimeException("Variable " + location.getName() + " not declared in method"); - } - } - if (!typedProgram.getCurrentClass().isCurrentMethodPresent() && typedProgram.getCurrentClass().isCurrentConstructorPresent()) { - if (typedProgram.getCurrentClass().getCurrentConstructor().isLocalVariableInConstructor(location.getName())) { - typeLeft = typedProgram.getCurrentClass().getCurrentConstructor().getLocalVariableType(location.getName()); - } else { - throw new RuntimeException("Variable " + location.getName() + " not declared in constructor"); - } - } - } + Type typeLeft = getTypeLeft(typedProgram); Type typeRight = value.typeCheck(typedProgram); if (typeLeft.equals(typeRight)) { @@ -59,11 +41,82 @@ public class TypedAssignment implements TypedStatement { throw new RuntimeException("type of left not equals with type of right"); } + private Type getTypeLeft(TypedProgram typedProgram) { + String name = location.getName(); + TypedClass currentClass = typedProgram.getCurrentClass(); + + if (currentClass.isThereField(name) && location.getField()) { + return currentClass.getFieldType(name); + } + + if (currentClass.isCurrentMethodPresent() && !currentClass.isCurrentConstructorPresent()) { + return getTypeFromMethodOrField(currentClass.getCurrentMethod(), name, currentClass); + } + + if (!currentClass.isCurrentMethodPresent() && currentClass.isCurrentConstructorPresent()) { + return getTypeFromConstructorOrField(currentClass.getCurrentConstructor(), name, currentClass); + } + + throw new RuntimeException("Variable " + name + " not declared"); + } + + private Type getTypeFromMethodOrField(TypedMethod currentMethod, String name, TypedClass currentClass) { + if (currentMethod.isLocalVariableInMethod(name)) { + return currentMethod.getLocalVariableType(name); + } else if (currentClass.isThereField(name)) { + return currentClass.getFieldType(name); + } else { + throw new RuntimeException("Variable " + name + " not declared in method"); + } + } + + private Type getTypeFromConstructorOrField(TypedConstructor currentConstructor, String name, TypedClass currentClass) { + if (currentConstructor.isLocalVariableInConstructor(name)) { + return currentConstructor.getLocalVariableType(name); + } else if (currentClass.isThereField(name)) { + return currentClass.getFieldType(name); + } else { + throw new RuntimeException("Variable " + name + " not declared in constructor"); + } + } + @Override public void codeGen(MethodContext ctx) { - if (value instanceof TypedIntLiteral) { - ctx.getMv().visitIntInsn(Opcodes.BIPUSH, ((TypedIntLiteral) value).getValue()); - ctx.getMv().visitVarInsn(Opcodes.ISTORE, ctx.getLocalVarIndex()); + if(value instanceof TypedNew) { + value.codeGen(ctx); + getOwnerChain(ctx); + } else { + ctx.pushStack("this"); + getOwnerChain(ctx); + value.codeGen(ctx); + } + + + //save value in field + if (location.getField()) { + + String receiver = ctx.getClassContext().getName(); + if (location.getRecursiveOwnerChain() != null) { + receiver = location.getRecursiveOwnerChain().getType().getReference(); + } + ctx.getMv().visitFieldInsn(Opcodes.PUTFIELD, receiver, location.getName(), value.getType().getDescriptor()); + System.out.println("PUTFIELD: " + receiver + " " + location.getName() + " " + value.getType().getDescriptor()); + } else { + if(value.getType().getKind() == Type.Kind.REFERENCE) { + System.out.println("ASTORE " + ctx.getLocalVar(location.getName()).get().index()); + ctx.getMv().visitVarInsn(Opcodes.ASTORE, ctx.getLocalVar(location.getName()).get().index()); + } else { + ctx.getMv().visitVarInsn(Opcodes.ISTORE, ctx.getLocalVar(location.getName()).get().index()); + } + } + //ctx.popStack(); + //ctx.popStack(); + } + + private void getOwnerChain(MethodContext ctx) { + if (location.getRecursiveOwnerChain() != null) { + location.getRecursiveOwnerChain().codeGen(ctx); + ctx.pushAnonToStack(); } } } diff --git a/src/main/java/de/maishai/typedast/typedclass/TypedBinary.java b/src/main/java/de/maishai/typedast/typedclass/TypedBinary.java index fcf73f7..5ebe4fd 100644 --- a/src/main/java/de/maishai/typedast/typedclass/TypedBinary.java +++ b/src/main/java/de/maishai/typedast/typedclass/TypedBinary.java @@ -8,6 +8,11 @@ import de.maishai.typedast.Type; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; +import org.objectweb.asm.Label; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; + +import java.util.Map; import static de.maishai.typedast.Help.TypedExpressionHelp.convertExpression; @@ -67,6 +72,139 @@ public class TypedBinary implements TypedExpression { @Override public void codeGen(MethodContext ctx) { + if (op == Operator.AND) { + Label end = new Label(); + Label returnTrue = new Label(); + Label returnFalse = new Label(); + left.codeGen(ctx); + ctx.getMv().visitJumpInsn(Opcodes.IFNE, returnFalse); + right.codeGen(ctx); + ctx.getMv().visitJumpInsn(Opcodes.IFNE, returnFalse); + ctx.getMv().visitJumpInsn(Opcodes.GOTO, returnTrue); + ctx.getMv().visitLabel(returnFalse); + ctx.getMv().visitInsn(Opcodes.ICONST_0); + ctx.getMv().visitJumpInsn(Opcodes.GOTO, end); + ctx.getMv().visitLabel(returnTrue); + ctx.getMv().visitInsn(Opcodes.ICONST_1); + ctx.getMv().visitLabel(end); + } else if (op == Operator.OR) { + Label end = new Label(); + Label returnTrue = new Label(); + Label returnFalse = new Label(); + left.codeGen(ctx); + ctx.getMv().visitJumpInsn(Opcodes.IFNE, returnTrue); + right.codeGen(ctx); + ctx.getMv().visitJumpInsn(Opcodes.IFNE, returnTrue); + ctx.getMv().visitJumpInsn(Opcodes.GOTO, returnFalse); + + ctx.getMv().visitLabel(returnFalse); + ctx.getMv().visitInsn(Opcodes.ICONST_0); + ctx.getMv().visitJumpInsn(Opcodes.GOTO, end); + ctx.getMv().visitLabel(returnTrue); + ctx.getMv().visitInsn(Opcodes.ICONST_1); + ctx.getMv().visitLabel(end); + } else if (op == Operator.EQ) { + Label end = new Label(); + Label returnTrue = new Label(); + Label returnFalse = new Label(); + left.codeGen(ctx); + right.codeGen(ctx); + ctx.getMv().visitJumpInsn(Opcodes.IF_ICMPNE, returnFalse); + ctx.getMv().visitJumpInsn(Opcodes.GOTO, returnTrue); + + ctx.getMv().visitLabel(returnFalse); + ctx.getMv().visitInsn(Opcodes.ICONST_0); + ctx.getMv().visitJumpInsn(Opcodes.GOTO, end); + ctx.getMv().visitLabel(returnTrue); + ctx.getMv().visitInsn(Opcodes.ICONST_1); + ctx.getMv().visitLabel(end); + } else if (op == Operator.GT) { + Label end = new Label(); + Label returnTrue = new Label(); + Label returnFalse = new Label(); + left.codeGen(ctx); + right.codeGen(ctx); + ctx.getMv().visitJumpInsn(Opcodes.IF_ICMPLE, returnFalse); + ctx.getMv().visitJumpInsn(Opcodes.GOTO, returnTrue); + + ctx.getMv().visitLabel(returnFalse); + ctx.getMv().visitInsn(Opcodes.ICONST_0); + ctx.getMv().visitJumpInsn(Opcodes.GOTO, end); + ctx.getMv().visitLabel(returnTrue); + ctx.getMv().visitInsn(Opcodes.ICONST_1); + ctx.getMv().visitLabel(end); + } else if (op == Operator.LT) { + Label end = new Label(); + Label returnTrue = new Label(); + Label returnFalse = new Label(); + left.codeGen(ctx); + right.codeGen(ctx); + ctx.getMv().visitJumpInsn(Opcodes.IF_ICMPGE, returnFalse); + ctx.getMv().visitJumpInsn(Opcodes.GOTO, returnTrue); + + ctx.getMv().visitLabel(returnFalse); + ctx.getMv().visitInsn(Opcodes.ICONST_0); + ctx.getMv().visitJumpInsn(Opcodes.GOTO, end); + ctx.getMv().visitLabel(returnTrue); + ctx.getMv().visitInsn(Opcodes.ICONST_1); + ctx.getMv().visitLabel(end); + } else if (op == Operator.GE) { + Label end = new Label(); + Label returnTrue = new Label(); + Label returnFalse = new Label(); + left.codeGen(ctx); + right.codeGen(ctx); + ctx.getMv().visitJumpInsn(Opcodes.IF_ICMPLT, returnFalse); + ctx.getMv().visitJumpInsn(Opcodes.GOTO, returnTrue); + + ctx.getMv().visitLabel(returnFalse); + ctx.getMv().visitInsn(Opcodes.ICONST_0); + ctx.getMv().visitJumpInsn(Opcodes.GOTO, end); + ctx.getMv().visitLabel(returnTrue); + ctx.getMv().visitInsn(Opcodes.ICONST_1); + ctx.getMv().visitLabel(end); + } else if (op == Operator.LE) { + Label end = new Label(); + Label returnTrue = new Label(); + Label returnFalse = new Label(); + left.codeGen(ctx); + right.codeGen(ctx); + ctx.getMv().visitJumpInsn(Opcodes.IF_ICMPGT, returnFalse); + ctx.getMv().visitJumpInsn(Opcodes.GOTO, returnTrue); + + ctx.getMv().visitLabel(returnFalse); + ctx.getMv().visitInsn(Opcodes.ICONST_0); + ctx.getMv().visitJumpInsn(Opcodes.GOTO, end); + ctx.getMv().visitLabel(returnTrue); + ctx.getMv().visitInsn(Opcodes.ICONST_1); + ctx.getMv().visitLabel(end); + } else if (op == Operator.NE) { + Label end = new Label(); + Label returnTrue = new Label(); + Label returnFalse = new Label(); + left.codeGen(ctx); + right.codeGen(ctx); + ctx.getMv().visitJumpInsn(Opcodes.IF_ICMPEQ, returnFalse); + ctx.getMv().visitJumpInsn(Opcodes.GOTO, returnTrue); + + ctx.getMv().visitLabel(returnFalse); + ctx.getMv().visitInsn(Opcodes.ICONST_0); + ctx.getMv().visitJumpInsn(Opcodes.GOTO, end); + ctx.getMv().visitLabel(returnTrue); + ctx.getMv().visitInsn(Opcodes.ICONST_1); + ctx.getMv().visitLabel(end); + } else { + left.codeGen(ctx); + right.codeGen(ctx); + if (op == Operator.ADD) { + ctx.getMv().visitInsn(Opcodes.IADD); + } else if (op == Operator.SUB) { + ctx.getMv().visitInsn(Opcodes.ISUB); + } else if (op == Operator.MUL) { + ctx.getMv().visitInsn(Opcodes.IMUL); + } + } + ctx.popStack(); } } diff --git a/src/main/java/de/maishai/typedast/typedclass/TypedBlock.java b/src/main/java/de/maishai/typedast/typedclass/TypedBlock.java index 0625aeb..58b5986 100644 --- a/src/main/java/de/maishai/typedast/typedclass/TypedBlock.java +++ b/src/main/java/de/maishai/typedast/typedclass/TypedBlock.java @@ -103,12 +103,12 @@ public class TypedBlock implements TypedNode { Type chekType = null; for (TypedStatement stmt : stmts) { stmt.typeCheck(typedProgram); - if(stmt instanceof TypedReturn returnStmt) { + if (stmt instanceof TypedReturn returnStmt) { chekType = returnStmt.getType(); } } - if(chekType == null) { + if (chekType == null) { chekType = Type.VOID; } type = chekType; @@ -117,7 +117,7 @@ public class TypedBlock implements TypedNode { public void codeGen(MethodContext ctx) { for (TypedLocalVariable var : vars) { - //var.codeGen(ctx); + ctx.registerVariable(var.getName(), var.getType()); } for (TypedStatement stmt : stmts) { stmt.codeGen(ctx); diff --git a/src/main/java/de/maishai/typedast/typedclass/TypedBoolLiteral.java b/src/main/java/de/maishai/typedast/typedclass/TypedBoolLiteral.java index aa8b9e6..c92301c 100644 --- a/src/main/java/de/maishai/typedast/typedclass/TypedBoolLiteral.java +++ b/src/main/java/de/maishai/typedast/typedclass/TypedBoolLiteral.java @@ -4,12 +4,14 @@ import de.maishai.ast.records.BoolLiteral; import de.maishai.typedast.MethodContext; import de.maishai.typedast.TypedExpression; import de.maishai.typedast.Type; +import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import org.objectweb.asm.Opcodes; @Data @NoArgsConstructor +@AllArgsConstructor public class TypedBoolLiteral implements TypedExpression { private Boolean value; @@ -32,10 +34,11 @@ public class TypedBoolLiteral implements TypedExpression { @Override public void codeGen(MethodContext ctx) { - if(value){ + if (value) { ctx.getMv().visitInsn(Opcodes.ICONST_1); - }else{ + } else { ctx.getMv().visitInsn(Opcodes.ICONST_0); } + ctx.pushInstantToStack(); } } diff --git a/src/main/java/de/maishai/typedast/typedclass/TypedBreak.java b/src/main/java/de/maishai/typedast/typedclass/TypedBreak.java index 54d32c6..4ff64ee 100644 --- a/src/main/java/de/maishai/typedast/typedclass/TypedBreak.java +++ b/src/main/java/de/maishai/typedast/typedclass/TypedBreak.java @@ -10,10 +10,6 @@ import lombok.Data; public class TypedBreak implements TypedStatement { private Type type = Type.VOID; - public TypedBreak convertToTypedBreak(TypedClass clas, Break unTypedBreak) { - return this; - } - @Override public Type typeCheck(TypedProgram typedProgram) { return type; diff --git a/src/main/java/de/maishai/typedast/typedclass/TypedCharLiteral.java b/src/main/java/de/maishai/typedast/typedclass/TypedCharLiteral.java index 08caf8d..74b71d7 100644 --- a/src/main/java/de/maishai/typedast/typedclass/TypedCharLiteral.java +++ b/src/main/java/de/maishai/typedast/typedclass/TypedCharLiteral.java @@ -4,9 +4,11 @@ import de.maishai.ast.records.CharLiteral; import de.maishai.typedast.MethodContext; import de.maishai.typedast.TypedExpression; import de.maishai.typedast.Type; +import lombok.AllArgsConstructor; import lombok.Data; @Data +@AllArgsConstructor public class TypedCharLiteral implements TypedExpression { private char value; private Type type; @@ -29,5 +31,6 @@ public class TypedCharLiteral implements TypedExpression { @Override public void codeGen(MethodContext ctx) { ctx.getMv().visitLdcInsn(value); + ctx.pushInstantToStack(); } } diff --git a/src/main/java/de/maishai/typedast/typedclass/TypedClass.java b/src/main/java/de/maishai/typedast/typedclass/TypedClass.java index 94dc6f9..bc61985 100644 --- a/src/main/java/de/maishai/typedast/typedclass/TypedClass.java +++ b/src/main/java/de/maishai/typedast/typedclass/TypedClass.java @@ -28,13 +28,11 @@ public class TypedClass implements TypedNode { private TypedConstructor currentConstructor; private Type type; - public TypedClass(TypedProgram typedProgram, Class c) { + public TypedClass(Class c) { className = c.classname(); type = Type.REFERENCE(className); - convertMethodsAndConstructorsAndFields(typedProgram, c); } - public boolean isParameterNameInCurrentConstructor(String parameterName) { if (currentConstructor == null) { return false; @@ -47,7 +45,7 @@ public class TypedClass implements TypedNode { return false; } - public void convertMethodsAndConstructorsAndFields(TypedProgram typedProgram, Class c){ + public void convertMethodsAndConstructorsAndFields(TypedProgram typedProgram, Class c) { // Am Anfang werden die Attribute, die Konstruktoren und Methoden in die jeweilige Liste eingefügt. // damit die Methoden verwendet werden können, bevor deren Blöcke ausgeführt werden for (Declaration declaration : c.fieldDeclarations()) { @@ -62,7 +60,7 @@ public class TypedClass implements TypedNode { } } - public void covertBlocksOfConstructorsAndMethods(TypedProgram typedProgram, Class c){ + public void covertBlocksOfConstructorsAndMethods(TypedProgram typedProgram, Class c) { // Hier werden die Blöcke der Konstruktoren ausgeführt int i = 0; for (Constructor constructor : c.constructors()) { @@ -119,6 +117,24 @@ public class TypedClass implements TypedNode { return null; } + public boolean isMethodOfCurrentClass(String methodName) { + for (TypedMethod m : typedMethods) { + if (m.getName().equals(methodName)) { + return true; + } + } + return false; + } + + public Type getMethodType(String methodName) { + for (TypedMethod m : typedMethods) { + if (m.getName().equals(methodName)) { + return m.getReturnType(); + } + } + return null; + } + public Type getParameterTypeInCurrentConstructor(String parameterName) { for (TypedParameter p : currentConstructor.getTypedParameters()) { if (p.getParaName().equals(parameterName)) { diff --git a/src/main/java/de/maishai/typedast/typedclass/TypedConstructor.java b/src/main/java/de/maishai/typedast/typedclass/TypedConstructor.java index 27c188a..9fa5953 100644 --- a/src/main/java/de/maishai/typedast/typedclass/TypedConstructor.java +++ b/src/main/java/de/maishai/typedast/typedclass/TypedConstructor.java @@ -53,11 +53,20 @@ public class TypedConstructor implements TypedNode { name = unTypedConstructor.className(); for (Parameter param : unTypedConstructor.params()) { - typedParameters.add(new TypedParameter(typedProgram, param)); + TypedParameter typedParameter = new TypedParameter(typedProgram, param); + checkIfParameterExists(typedParameter.getParaName()); + typedParameters.add(typedParameter); + localVariables.add(new TypedLocalVariable(typedParameter.getParaName(), typedParameter.getType())); } type = Type.VOID; } + public void checkIfParameterExists(String paraName) { + if (typedParameters.stream().anyMatch(parameter -> parameter.getParaName().equals(paraName))) { + throw new RuntimeException("Parameter " + paraName + " already exists"); + } + } + public void convertToBlock(TypedProgram typedProgram, Constructor unTypedConstructor) { this.typedBlock = new TypedBlock(typedProgram, unTypedConstructor.block()); typeCheck(typedProgram); @@ -76,12 +85,15 @@ public class TypedConstructor implements TypedNode { public void codeGen(ClassContext ctx) { int accessModifier = Opcodes.ACC_PUBLIC; // ist laut Andi ok - MethodVisitor mv = ctx.getCw().visitMethod(accessModifier, "", CodeGenUtils.generateDescriptor(typedParameters, Type.VOID), null, null); + MethodVisitor mv = ctx.getCw().visitMethod(accessModifier, "", CodeGenUtils.generateDescriptor(typedParameters.stream().map(TypedParameter::getType).toList(), Type.VOID), null, null); + System.out.println("Visiting method: " + "" + CodeGenUtils.generateDescriptor(typedParameters.stream().map(TypedParameter::getType).toList(), Type.VOID)); MethodContext mctx = new MethodContext(ctx, mv); typedParameters.forEach(param -> mctx.registerVariable(param.getParaName(), param.getType())); //super(); mctx.pushStack("this"); mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", "", "()V", false); + System.out.println("INVOKESPECIAL: " + "java/lang/Object" + " " + "" + " " + "()V"); + mctx.popStack(); typedBlock.codeGen(mctx); diff --git a/src/main/java/de/maishai/typedast/typedclass/TypedDeclaration.java b/src/main/java/de/maishai/typedast/typedclass/TypedDeclaration.java index 4d9feb1..d653b54 100644 --- a/src/main/java/de/maishai/typedast/typedclass/TypedDeclaration.java +++ b/src/main/java/de/maishai/typedast/typedclass/TypedDeclaration.java @@ -9,7 +9,6 @@ import lombok.NoArgsConstructor; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.Opcodes; -import static de.maishai.typedast.Type.Kind.REFERENCE; @Data @AllArgsConstructor @@ -30,27 +29,17 @@ public final class TypedDeclaration implements TypedNode { @Override public Type typeCheck(TypedProgram typedProgram) { + if (type.getReference() != null && !typedProgram.getCurrentClass().getClassName().equals(type.getReference())) { + if (!typedProgram.isTypedClassPresent(type.getReference())) { + throw new RuntimeException("Type " + type.getReference() + " not found"); + } + } if (typedProgram.getCurrentClass().isThereField(name)) { throw new RuntimeException("Field " + name + " already declared"); } - - if (type.getKind() == REFERENCE) { - if (!type.getReference().equals(typedProgram.getCurrentClass().getClassName())) { - throw new RuntimeException("Field " + name + " has wrong type"); - } - - } - return type; } - /* - public void codeGen(MethodVisitor mv, MethodContext ctx) { - System.out.println("Generating code for local variable " + name); - int index = ctx.addVariable(name); - mv.visitLocalVariable(name, type.getDescriptor(), null, ctx.getStartLabel(), ctx.getEndLabel(), index); - } - */ public void codeGen(ClassWriter cw) { int access = Opcodes.ACC_PUBLIC; // laut Andi ist es ok, dass alle Felder public sind cw.visitField(access, name, type.getDescriptor(), null, null).visitEnd(); diff --git a/src/main/java/de/maishai/typedast/typedclass/TypedFieldVarAccess.java b/src/main/java/de/maishai/typedast/typedclass/TypedFieldVarAccess.java index 2030d52..74ab48a 100644 --- a/src/main/java/de/maishai/typedast/typedclass/TypedFieldVarAccess.java +++ b/src/main/java/de/maishai/typedast/typedclass/TypedFieldVarAccess.java @@ -7,6 +7,10 @@ import de.maishai.typedast.Type; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; + +import java.util.Map; import static de.maishai.typedast.Help.TypedExpressionHelp.convertExpression; @@ -32,49 +36,88 @@ public class TypedFieldVarAccess implements TypedExpression { @Override public Type typeCheck(TypedProgram typedProgram) { if (field) { - if (typedProgram.getCurrentClass().isThereField(name)) { - type = typedProgram.getCurrentClass().getFieldType(name); - return typedProgram.getCurrentClass().getFieldType(name); - }else{ - throw new RuntimeException("Field " + name + " not declared "); - } + type = checkFieldOrMethodType(typedProgram); + return type; } else { - if (typedProgram.getCurrentClass().isCurrentConstructorPresent()) { - if (typedProgram.getCurrentClass().isParameterNameInCurrentConstructor(name)) { - type = typedProgram.getCurrentClass().getParameterTypeInCurrentConstructor(name); - return type; - } else if (typedProgram.getCurrentClass().getCurrentConstructor().isLocalVariablePresent(name)) { - type = typedProgram.getCurrentClass().getCurrentConstructor().getLocalVariableType(name); - return type; - } else if(typedProgram.getCurrentClass().isThereField(name)){ - type = typedProgram.getCurrentClass().getFieldType(name); - return type; - } - else { - throw new RuntimeException("Variable " + name + " not declared in constructor"); - } - - } else if (typedProgram.getCurrentClass().isCurrentMethodPresent()) { - if (typedProgram.getCurrentClass().isParameterWitNameInMethod(name)) { - type = typedProgram.getCurrentClass().getParameterTypeInCurrentMethod(name); - return type; - } else if (typedProgram.getCurrentClass().getCurrentMethod().isLocalVariablePresent(name)) { - type = typedProgram.getCurrentClass().getCurrentMethod().getLocalVariableType(name); - return type; - } else if(typedProgram.getCurrentClass().isThereField(name)){ - type = typedProgram.getCurrentClass().getFieldType(name); - return type; - } - else { - throw new RuntimeException("Variable " + name + " not declared in method"); - } - } - throw new RuntimeException("Variable " + name + " not declared "); + type = checkVariableType(typedProgram); + return type; } } + private Type checkFieldOrMethodType(TypedProgram typedProgram) { + if (typedProgram.getCurrentClass().isThereField(name)) { + type = typedProgram.getCurrentClass().getFieldType(name); + return type; + } else if (typedProgram.getCurrentClass().isMethodOfCurrentClass(name)) { + type = typedProgram.getCurrentClass().getMethodType(name); + return type; + } else if (recursiveOwnerChain instanceof TypedFieldVarAccess typedFieldVarAccess) { + type = typedProgram.getCurrentClass().getFieldType(typedFieldVarAccess.getName()); + return type; + } else { + throw new RuntimeException("Field " + name + " not declared"); + } + } + + private Type checkVariableType(TypedProgram typedProgram) { + if (typedProgram.getCurrentClass().isCurrentConstructorPresent()) { + return checkConstructorVariableType(typedProgram); + } else if (typedProgram.getCurrentClass().isCurrentMethodPresent()) { + return checkMethodVariableType(typedProgram); + } else { + throw new RuntimeException("Variable " + name + " not declared"); + } + } + + private Type checkConstructorVariableType(TypedProgram typedProgram) { + if (typedProgram.getCurrentClass().isParameterNameInCurrentConstructor(name)) { + type = typedProgram.getCurrentClass().getParameterTypeInCurrentConstructor(name); + } else if (typedProgram.getCurrentClass().getCurrentConstructor().isLocalVariablePresent(name)) { + type = typedProgram.getCurrentClass().getCurrentConstructor().getLocalVariableType(name); + } else { + return checkFieldOrMethodOrRecursiveType(typedProgram); + } + return type; + } + + private Type checkMethodVariableType(TypedProgram typedProgram) { + if (typedProgram.getCurrentClass().isParameterWitNameInMethod(name)) { + type = typedProgram.getCurrentClass().getParameterTypeInCurrentMethod(name); + } else if (typedProgram.getCurrentClass().getCurrentMethod().isLocalVariablePresent(name)) { + type = typedProgram.getCurrentClass().getCurrentMethod().getLocalVariableType(name); + } else { + return checkFieldOrMethodOrRecursiveType(typedProgram); + } + return type; + } + + private Type checkFieldOrMethodOrRecursiveType(TypedProgram typedProgram) { + if (typedProgram.getCurrentClass().isThereField(name)) { + type = typedProgram.getCurrentClass().getFieldType(name); + } else if (typedProgram.getCurrentClass().isMethodOfCurrentClass(name)) { + type = typedProgram.getCurrentClass().getMethodType(name); + } else if (recursiveOwnerChain instanceof TypedFieldVarAccess typedFieldVarAccess) { + type = typedProgram.getCurrentClass().getFieldType(typedFieldVarAccess.getName()); + } else { + throw new RuntimeException("Variable " + name + " not declared"); + } + return type; + } + @Override public void codeGen(MethodContext ctx) { - + if (recursiveOwnerChain != null) { + recursiveOwnerChain.codeGen(ctx); + } + if (field && recursiveOwnerChain == null) { + ctx.pushStack("this"); + } + if (field) { + ctx.getMv().visitFieldInsn(Opcodes.GETFIELD, recursiveOwnerChain.getType().getReference(), name, type.getDescriptor()); + } else { + int loadOpcode = type.getKind() == Type.Kind.REFERENCE ? Opcodes.ALOAD : Opcodes.ILOAD; + ctx.getMv().visitVarInsn(loadOpcode, ctx.getLocalVar(name).get().index()); + System.out.println(loadOpcode == Opcodes.ALOAD ? "ALOAD " + ctx.getLocalVar(name).get().index() : "ILOAD " + ctx.getLocalVar(name).get().index()); + } } } diff --git a/src/main/java/de/maishai/typedast/typedclass/TypedIfElse.java b/src/main/java/de/maishai/typedast/typedclass/TypedIfElse.java index 69a5240..8fe4e19 100644 --- a/src/main/java/de/maishai/typedast/typedclass/TypedIfElse.java +++ b/src/main/java/de/maishai/typedast/typedclass/TypedIfElse.java @@ -2,6 +2,7 @@ package de.maishai.typedast.typedclass; import de.maishai.ast.records.*; import de.maishai.typedast.*; +import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import org.objectweb.asm.Label; @@ -11,6 +12,7 @@ import static de.maishai.typedast.Help.TypedExpressionHelp.convertExpression; @Data @NoArgsConstructor +@AllArgsConstructor public class TypedIfElse implements TypedStatement { private TypedExpression typedCon; private TypedBlock ifTypedBlock; diff --git a/src/main/java/de/maishai/typedast/typedclass/TypedIntLiteral.java b/src/main/java/de/maishai/typedast/typedclass/TypedIntLiteral.java index 41634f7..9a43fa5 100644 --- a/src/main/java/de/maishai/typedast/typedclass/TypedIntLiteral.java +++ b/src/main/java/de/maishai/typedast/typedclass/TypedIntLiteral.java @@ -7,6 +7,10 @@ import de.maishai.typedast.Type; import lombok.AllArgsConstructor; import lombok.Data; import lombok.RequiredArgsConstructor; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; + +import java.util.Map; @Data @AllArgsConstructor @@ -37,6 +41,16 @@ public class TypedIntLiteral implements TypedExpression { @Override public void codeGen(MethodContext ctx) { - ctx.getMv().visitLdcInsn(value); + if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) { + ctx.getMv().visitIntInsn(Opcodes.BIPUSH, value); + System.out.println("BIPUSH " + value); + } else if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) { + ctx.getMv().visitIntInsn(Opcodes.SIPUSH, value); + System.out.println("SIPUSH " + value); + } else { + ctx.getMv().visitLdcInsn(value); + System.out.println("LDC " + value); + } + ctx.pushInstantToStack(); } } diff --git a/src/main/java/de/maishai/typedast/typedclass/TypedMethod.java b/src/main/java/de/maishai/typedast/typedclass/TypedMethod.java index 5b4eb3e..97e787f 100644 --- a/src/main/java/de/maishai/typedast/typedclass/TypedMethod.java +++ b/src/main/java/de/maishai/typedast/typedclass/TypedMethod.java @@ -2,6 +2,7 @@ package de.maishai.typedast.typedclass; import de.maishai.ast.records.Method; import de.maishai.typedast.*; +import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import org.objectweb.asm.MethodVisitor; @@ -12,6 +13,7 @@ import java.util.List; @Data @NoArgsConstructor +@AllArgsConstructor public class TypedMethod implements TypedNode { private String name; private Type returnType; @@ -28,7 +30,10 @@ public class TypedMethod implements TypedNode { name = unTypedMethod.methodName(); returnType = unTypedMethod.type(); for (var parameter : unTypedMethod.params()) { - typedParameters.add(new TypedParameter(typedProgram, parameter)); + TypedParameter typedParameter = new TypedParameter(typedProgram, parameter); + checkIfParameterExists(typedParameter.getParaName()); + typedParameters.add(typedParameter); + localVariables.add(new TypedLocalVariable(typedParameter.getParaName(), typedParameter.getType())); } typedProgram.getCurrentClass().getTypedMethods().stream().filter(method -> method.equals(this)).findFirst().ifPresentOrElse( @@ -38,6 +43,12 @@ public class TypedMethod implements TypedNode { }); } + public void checkIfParameterExists(String parameterName) { + if (typedParameters.stream().anyMatch(parameter -> parameter.getParaName().equals(parameterName))) { + throw new RuntimeException("Parameter " + parameterName + " already exists"); + } + } + public void convertToTypedBlock(TypedProgram typedProgram, Method unTypedMethod) { typedBlock = new TypedBlock(typedProgram, unTypedMethod.block()); typeCheck(typedProgram); @@ -109,7 +120,7 @@ public class TypedMethod implements TypedNode { public void codeGen(ClassContext ctx) { int accessModifier = Opcodes.ACC_PUBLIC; // ist laut Andi ok MethodVisitor mv = ctx.getCw().visitMethod(accessModifier, name, - CodeGenUtils.generateDescriptor(typedParameters, returnType), null, null); + CodeGenUtils.generateDescriptor(typedParameters.stream().map(TypedParameter::getType).toList(), returnType), null, null); MethodContext context = new MethodContext(ctx, mv); typedParameters.forEach(param -> context.registerVariable(param.getParaName(), param.getType())); diff --git a/src/main/java/de/maishai/typedast/typedclass/TypedMethodCall.java b/src/main/java/de/maishai/typedast/typedclass/TypedMethodCall.java index e3fc6c9..83353a4 100644 --- a/src/main/java/de/maishai/typedast/typedclass/TypedMethodCall.java +++ b/src/main/java/de/maishai/typedast/typedclass/TypedMethodCall.java @@ -3,18 +3,20 @@ package de.maishai.typedast.typedclass; import de.maishai.ast.records.Expression; import de.maishai.ast.records.MethodCall; import de.maishai.typedast.*; +import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import java.util.ArrayList; import java.util.List; +import java.util.Optional; import static de.maishai.typedast.Help.TypedExpressionHelp.convertExpression; -//TODO: test this after fixing error from parser @Data @NoArgsConstructor +@AllArgsConstructor public class TypedMethodCall implements TypedExpression, TypedStatement { private TypedFieldVarAccess recipient; private List args = new ArrayList<>(); @@ -26,38 +28,60 @@ public class TypedMethodCall implements TypedExpression, TypedStatement { public void convertToTypedMethodCall(TypedProgram typedProgram, MethodCall unTypedMethodCall) { recipient = new TypedFieldVarAccess(typedProgram, unTypedMethodCall.recipient()); - for (Expression arg : unTypedMethodCall.args()) { - args.add(convertExpression(typedProgram, arg)); - } + recipient.typeCheck(typedProgram); + for (Expression arg : unTypedMethodCall.args()) { + args.add(convertExpression(typedProgram, arg)); + } } @Override public Type typeCheck(TypedProgram typedProgram) { - if (typedProgram.getCurrentClass().isCurrentMethodPresent() || typedProgram.getCurrentClass().isCurrentConstructorPresent()) { + String ownerChainName = null; + if (recipient.getRecursiveOwnerChain() != null) { + ownerChainName = recipient.getRecursiveOwnerChain().getType().getReference(); + } - List methods = typedProgram.getCurrentClass().getTypedMethods().stream() - .filter(method -> method.getName().equals(recipient.getName())) - .toList(); - - for (TypedMethod method : methods) { - if (method.getTypedParameters().size() == args.size()) { - boolean allMatch = true; - for (int i = 0; i < args.size(); i++) { - if (!args.get(i).typeCheck(typedProgram).equals(method.getTypedParameters().get(i).getType())) { - allMatch = false; - break; - } - } - if (allMatch) { - type = method.getReturnType(); - return type; - } - } + if (!typedProgram.getCurrentClass().getClassName().equals(ownerChainName) && ownerChainName != null) { + Optional matchingMethod = findMatchingMethod(typedProgram.getTypedClass(ownerChainName), recipient.getName()); + if (matchingMethod.isPresent()) { + type = matchingMethod.get(); + return type; } } + + if (typedProgram.getCurrentClass().isCurrentMethodPresent() || typedProgram.getCurrentClass().isCurrentConstructorPresent()) { + Optional matchingMethod = findMatchingMethod(typedProgram.getCurrentClass(), recipient.getName()); + if (matchingMethod.isPresent()) { + type = matchingMethod.get(); + return type; + } + } + throw new RuntimeException("Method not found"); } + public Optional findMatchingMethod(TypedClass ownerChain, String methodName) { + List methods = ownerChain.getTypedMethods().stream() + .filter(method -> method.getName().equals(methodName)) + .toList(); + + for (TypedMethod method : methods) { + if (method.getTypedParameters().size() == args.size()) { + boolean allMatch = true; + for (int i = 0; i < args.size(); i++) { + if (!args.get(i).getType().equals(method.getTypedParameters().get(i).getType())) { + allMatch = false; + break; + } + } + if (allMatch) { + return Optional.of(method.getReturnType()); + } + } + } + + return Optional.empty(); + } @Override public void codeGen(MethodContext ctx) { diff --git a/src/main/java/de/maishai/typedast/typedclass/TypedNew.java b/src/main/java/de/maishai/typedast/typedclass/TypedNew.java index 6b8f322..c5cc3b5 100644 --- a/src/main/java/de/maishai/typedast/typedclass/TypedNew.java +++ b/src/main/java/de/maishai/typedast/typedclass/TypedNew.java @@ -3,7 +3,10 @@ package de.maishai.typedast.typedclass; import de.maishai.ast.records.Expression; import de.maishai.ast.records.New; import de.maishai.typedast.*; +import lombok.AllArgsConstructor; import lombok.Data; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; import java.util.ArrayList; import java.util.List; @@ -11,6 +14,7 @@ import java.util.List; import static de.maishai.typedast.Help.TypedExpressionHelp.convertExpression; @Data +@AllArgsConstructor public class TypedNew implements TypedExpression, TypedStatement { private Type type; private List args = new ArrayList<>(); @@ -28,6 +32,11 @@ public class TypedNew implements TypedExpression, TypedStatement { @Override public Type typeCheck(TypedProgram typedProgram) { + + if (typedProgram.isTypedClassPresent(type.getReference())) { + return Type.REFERENCE(type.getReference()); + } + for (var constructor : typedProgram.getCurrentClass().getTypedConstructors()) { if (constructor.getTypedParameters().size() == args.size()) { boolean valid = true; @@ -48,6 +57,21 @@ public class TypedNew implements TypedExpression, TypedStatement { @Override public void codeGen(MethodContext ctx) { + //pop the stack + //ctx.popStack(); + //ctx.getMv().visitInsn(Opcodes.POP); + //System.out.println("Popped stack"); + ctx.getMv().visitTypeInsn(Opcodes.NEW, type.getReference()); + System.out.println("NEW " + type.getReference()); + ctx.pushAnonToStack(); + ctx.getMv().visitInsn(Opcodes.DUP); + System.out.println("DUP"); + ctx.pushAnonToStack(); + for (TypedExpression arg : args) { + arg.codeGen(ctx); + } + ctx.getMv().visitMethodInsn(Opcodes.INVOKESPECIAL, type.getReference(), "", CodeGenUtils.generateDescriptor(args.stream().map(TypedExpression::getType).toList(), Type.VOID), false); + System.out.println("INVOKESPECIAL " + type.getReference() + " " + CodeGenUtils.generateDescriptor(args.stream().map(TypedExpression::getType).toList(), Type.VOID)); } } diff --git a/src/main/java/de/maishai/typedast/typedclass/TypedProgram.java b/src/main/java/de/maishai/typedast/typedclass/TypedProgram.java index 1e52857..d30440b 100644 --- a/src/main/java/de/maishai/typedast/typedclass/TypedProgram.java +++ b/src/main/java/de/maishai/typedast/typedclass/TypedProgram.java @@ -19,16 +19,23 @@ public class TypedProgram { public void startConversion(Program program) { + // Initialisiere die Klassen nur mit den Klassennamen und deren Typ + for (var clas : program.classes()) { + typedClasses.add(new TypedClass(clas)); + } + + // Konvertiere die Methoden, Konstruktoren und Felder von den jeweiligen Klassen int k = 0; for (var clas : program.classes()) { enterCurrentClass(typedClasses.get(k)); - typedClasses.add(new TypedClass(this, clas)); + typedClasses.get(k).convertMethodsAndConstructorsAndFields(this, clas); exitCurrentClass(); k++; } + // Konvertiere die Blöcke der Konstruktoren und Methoden von den jeweiligen Klassen int i = 0; - for(var clas : program.classes()){ + for (var clas : program.classes()) { enterCurrentClass(typedClasses.get(i)); typedClasses.get(i).covertBlocksOfConstructorsAndMethods(this, clas); exitCurrentClass(); @@ -40,8 +47,8 @@ public class TypedProgram { return typedClasses.stream().filter(clas -> clas.getClassName().equals(className)).findFirst().get(); } - public boolean isCurrentClassPresent() { - return currentClass != null; + public boolean isTypedClassPresent(String className) { + return typedClasses.stream().anyMatch(clas -> clas.getClassName().equals(className)); } public void enterCurrentClass(TypedClass clas) { @@ -52,4 +59,18 @@ public class TypedProgram { currentClass = null; } + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null || getClass() != obj.getClass()) return false; + TypedProgram other = (TypedProgram) obj; + if(typedClasses.equals(other.typedClasses) && + (currentClass == null && other.currentClass == null + || currentClass.equals(other.currentClass))) { + return true; + } else { + System.out.println("TypedPrograms are not equal:\n" + this.typedClasses + "\n" + other.typedClasses + "\n"); + return false; + } + } } diff --git a/src/main/java/de/maishai/typedast/typedclass/TypedReturn.java b/src/main/java/de/maishai/typedast/typedclass/TypedReturn.java index 9995c2e..e11f592 100644 --- a/src/main/java/de/maishai/typedast/typedclass/TypedReturn.java +++ b/src/main/java/de/maishai/typedast/typedclass/TypedReturn.java @@ -3,6 +3,7 @@ package de.maishai.typedast.typedclass; import de.maishai.ast.records.*; import de.maishai.typedast.*; +import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import org.objectweb.asm.Opcodes; @@ -11,6 +12,7 @@ import static de.maishai.typedast.Help.TypedExpressionHelp.convertExpression; @Data @NoArgsConstructor +@AllArgsConstructor public class TypedReturn implements TypedStatement { private TypedExpression ret; private Type type; @@ -21,9 +23,9 @@ public class TypedReturn implements TypedStatement { public void convertToTypedReturn(TypedProgram typedProgram, Return unTypedReturn) { ret = convertExpression(typedProgram, unTypedReturn.ret()); - if(ret == null){ + if (ret == null) { type = Type.VOID; - }else{ + } else { type = ret.getType(); } } @@ -48,6 +50,7 @@ public class TypedReturn implements TypedStatement { if (ret == null) { ctx.getMv().visitInsn(Opcodes.RETURN); } else { + System.out.println("return: " + ret); ret.codeGen(ctx); if (ret.getType().getKind() != Type.Kind.REFERENCE) { ctx.getMv().visitInsn(Opcodes.IRETURN); diff --git a/src/main/java/de/maishai/typedast/typedclass/TypedUnary.java b/src/main/java/de/maishai/typedast/typedclass/TypedUnary.java index a1fdd84..cc2dbfa 100644 --- a/src/main/java/de/maishai/typedast/typedclass/TypedUnary.java +++ b/src/main/java/de/maishai/typedast/typedclass/TypedUnary.java @@ -47,11 +47,11 @@ public class TypedUnary implements TypedExpression { @Override public void codeGen(MethodContext ctx) { right.codeGen(ctx); - if(op == UnaryOperator.NOT){ + if (op == UnaryOperator.NOT) { ctx.getMv().visitInsn(Opcodes.ICONST_1); ctx.getMv().visitInsn(Opcodes.IXOR); } - if(op == UnaryOperator.SUB){ + if (op == UnaryOperator.SUB) { ctx.getMv().visitInsn(Opcodes.INEG); } } diff --git a/src/main/resources/AbstractSyntax/AbstractSyntax_ClassWithConstructor.java b/src/main/resources/AbstractSyntax/AbstractSyntax_ClassWithConstructor.java index 49d6816..ec616c8 100644 --- a/src/main/resources/AbstractSyntax/AbstractSyntax_ClassWithConstructor.java +++ b/src/main/resources/AbstractSyntax/AbstractSyntax_ClassWithConstructor.java @@ -165,7 +165,6 @@ public class AbstractSyntax_ClassWithConstructor { localVariables, statementList ); - return new Constructor( "ClassWithConstructor", parameters, diff --git a/src/main/resources/AbstractSyntax/AbstractSyntax_ComplexClass.java b/src/main/resources/AbstractSyntax/AbstractSyntax_ComplexClass.java new file mode 100644 index 0000000..6fee8c7 --- /dev/null +++ b/src/main/resources/AbstractSyntax/AbstractSyntax_ComplexClass.java @@ -0,0 +1,902 @@ +//public class ComplexClass { +// +// int x; +// int y; +// ComplexClass b; +// ComplexClass c; +// +// public ComplexClass() { +// this.y = 10; +// this.x = 2; +// int i; +// for (i = 0; i < (this.y + 1); i = i + 1) { +// int j; +// for (j = 0; j < this.y; j += 1) { +// this.x = this.x * this.x; +// if (this.x == 100) { +// break; +// } +// } +// } +// this.y = 2; +// do { +// this.y = this.y + 1; +// } while (this.y < 10); +// +// int k; +// k = 0; +// for (k = 0; k < 10; k = k + 1) { +// if (k == 5) { +// return this; +// } +// } +// +// } +// +// public ComplexClass(int x) { +// this.b = new ComplexClass(); +// this.c = new ComplexClass(); +// this.x = x; +// this.b.x = 7; +// this.b.y = 13; +// this.c.x = this.b.getX() * this.b.y * this.b.getX('g'); +// this.c.y = 25; +// } +// +// public ComplexClass(int x, int y) { +// this.x = x; +// this.y = y; +// } +// +// public ComplexClass initComplexClass(int x) { +// int a; +// a = 10; +// this.b = new ComplexClass(x); +// this.b.x = 10 + a; +// this.b.y = 20; +// this.b.c.x = 20 + a; +// if (methodCall()) { +// this.b.getC().b.y = this.b.x; +// } +// return this.b; +// } +// +// public ComplexClass init(int x, int y) { +// return new ComplexClass(x, y); +// } +// +// public ComplexClass(int x, int y, char z) { +// this.x = x; +// this.y = y; +// } +// +// public int getX(char z) { +// return this.x; +// } +// +// public ComplexClass getC() { +// return this.c; +// } +// +// public int getX() { +// return this.x; +// } +// +// public boolean methodCall() { +// return false; +// } +// +//} + + +import de.maishai.ast.Operator; +import de.maishai.ast.records.*; +import de.maishai.ast.records.Class; +import de.maishai.typedast.Type; + +import java.util.List; + +@SuppressWarnings("DuplicateExpressions") +public class AbstractSyntax_ComplexClass { + public static Program get() { + List declarationList = List.of( + new Declaration( + "x", + Type.INT + ), + new Declaration( + "y", + Type.INT + ), + new Declaration( + "b", + Type.REFERENCE("ComplexClass") + ), + new Declaration( + "c", + Type.REFERENCE("ComplexClass") + ) + ); + List methodList = getMethods(); + List constructorList = getConstructors(); + return new Program( + List.of( + new Class( + "ComplexClass", + declarationList, + methodList, + constructorList + ) + ) + ); + } + + private static List getConstructors() { + return List.of( + getConstructor1(), + getConstructor2(), + getConstructor3(), + getConstructor4() + ); + } + + private static Constructor getConstructor1() { + Block block = new Block( + List.of( + new Declaration( + "i", + Type.INT + ), + new Declaration( + "k", + Type.INT + ) + ), + List.of( + new Assignment( + new FieldVarAccess( + true, + null, + "y"), + new IntLiteral(10) + ), + new Assignment( + new FieldVarAccess( + true, + null, + "x"), + new IntLiteral(2) + ), + new For( + new Assignment( + new FieldVarAccess( + false, + null, + "i"), + new IntLiteral(0) + ), + new Binary( + new FieldVarAccess( + false, + null, + "i"), + Operator.LT, + new Binary( + new FieldVarAccess( + true, + null, + "y"), + Operator.ADD, + new IntLiteral(1) + ) + ), + new Assignment( + new FieldVarAccess( + false, + null, + "i"), + new Binary( + new FieldVarAccess( + false, + null, + "i"), + Operator.ADD, + new IntLiteral(1) + ) + ), + new Block( + List.of( + new Declaration( + "j", + Type.INT + ) + ), + List.of( + new For( + new Assignment( + new FieldVarAccess( + false, + null, + "j"), + new IntLiteral(0) + ), + new Binary( + new FieldVarAccess( + false, + null, + "j"), + Operator.LT, + new FieldVarAccess( + true, + null, + "y" + ) + ), + new Assignment( + new FieldVarAccess( + false, + null, + "j"), + new Binary( + new FieldVarAccess( + false, + null, + "j"), + Operator.ADD, + new IntLiteral(1) + ) + ), + new Block( + List.of(), + List.of( + new Assignment( + new FieldVarAccess( + true, + null, + "x"), + new Binary( + new FieldVarAccess( + true, + null, + "x"), + Operator.MUL, + new FieldVarAccess( + true, + null, + "x" + ) + ) + ), + new IfElse( + new Binary( + new FieldVarAccess( + true, + null, + "x"), + Operator.EQ, + new IntLiteral(100) + ), + new Block( + List.of(), + List.of( + new Break() + ) + ), + null + ) + ) + ) + ) + ) + ) + ), + new Assignment( + new FieldVarAccess( + true, + null, + "y"), + new IntLiteral(2) + ), + new DoWhile( + new Block( + List.of(), + List.of( + new Assignment( + new FieldVarAccess( + true, + null, + "y"), + new Binary( + new FieldVarAccess( + true, + null, + "y"), + Operator.ADD, + new IntLiteral(1) + ) + ) + ) + ), + new Binary( + new FieldVarAccess( + true, + null, + "y"), + Operator.LT, + new IntLiteral(10) + ) + ), + new Assignment( + new FieldVarAccess( + false, + null, + "k"), + new IntLiteral(0) + ), + new For( + new Assignment( + new FieldVarAccess( + false, + null, + "k"), + new IntLiteral(0) + ), + new Binary( + new FieldVarAccess( + false, + null, + "k"), + Operator.LT, + new IntLiteral(10) + ), + new Assignment( + new FieldVarAccess( + false, + null, + "k"), + new Binary( + new FieldVarAccess( + false, + null, + "k"), + Operator.ADD, + new IntLiteral(1) + ) + ), + new Block( + List.of(), + List.of( + new IfElse( + new Binary( + new FieldVarAccess( + false, + null, + "k"), + Operator.EQ, + new IntLiteral(5) + ), + new Block( + List.of(), + List.of( + new Return( + new This() + ) + ) + ), + null + ) + ) + ) + ) + ) + ); + return new Constructor( + "ComplexClass", + List.of(), + block + ); + } + + private static Constructor getConstructor2() { + Block block = new Block( + List.of(), + List.of( + new Assignment( + new FieldVarAccess( + true, + null, + "b"), + new New( + Type.REFERENCE("ComplexClass"), + List.of() + ) + ), + new Assignment( + new FieldVarAccess( + true, + null, + "c"), + new New( + Type.REFERENCE("ComplexClass"), + List.of() + ) + ), + new Assignment( + new FieldVarAccess( + true, + null, + "x"), + new FieldVarAccess( + false, + null, + "x" + ) + ), + new Assignment( + new FieldVarAccess( + true, + new FieldVarAccess( + false, + null, + "b"), + "x"), + new IntLiteral(7) + ), + new Assignment( + new FieldVarAccess( + true, + new FieldVarAccess( + false, + null, + "b"), + "y"), + new IntLiteral(13) + ), + new Assignment( + new FieldVarAccess( + true, + new FieldVarAccess( + false, + null, + "c"), + "x"), + new Binary( + new Binary( + new MethodCall( + new FieldVarAccess( + true, + new FieldVarAccess( + false, + null, + "b"), + "getX" + ), + List.of() + ), + Operator.MUL, + new FieldVarAccess( + true, + new FieldVarAccess( + false, + null, + "b"), + "y" + ) + ), + Operator.MUL, + new MethodCall( + new FieldVarAccess( + true, + new FieldVarAccess( + false, + null, + "b"), + "getX" + ), + List.of( + new CharLiteral('g') + ) + ) + ) + ), + new Assignment( + new FieldVarAccess( + true, + new FieldVarAccess( + false, + null, + "c"), + "y"), + new IntLiteral(25) + ) + ) + ); + return new Constructor( + "ComplexClass", + List.of( + new Parameter( + "x", + Type.INT + ) + ), + block + ); + } + + private static Constructor getConstructor3() { + Block block = new Block( + List.of(), + List.of( + new Assignment( + new FieldVarAccess( + true, + null, + "x"), + new FieldVarAccess( + false, + null, + "x" + ) + ), + new Assignment( + new FieldVarAccess( + true, + null, + "y"), + new FieldVarAccess( + false, + null, + "y" + ) + ) + ) + ); + return new Constructor( + "ComplexClass", + List.of( + new Parameter( + "x", + Type.INT + ), + new Parameter( + "y", + Type.INT + ) + ), + block + ); + } + + private static Constructor getConstructor4() { + Block block = new Block( + List.of(), + List.of( + new Assignment( + new FieldVarAccess( + true, + null, + "x"), + new FieldVarAccess( + false, + null, + "x" + ) + ), + new Assignment( + new FieldVarAccess( + true, + null, + "y"), + new FieldVarAccess( + false, + null, + "y" + ) + ) + ) + ); + return new Constructor( + "ComplexClass", + List.of( + new Parameter( + "x", + Type.INT + ), + new Parameter( + "y", + Type.INT + ), + new Parameter( + "z", + Type.CHAR + ) + ), + block + ); + } + + private static List getMethods() { + return List.of( + getMethod1(), + getMethod2(), + getMethod3(), + getMethod4(), + getMethod5(), + getMethod6() + ); + } + + private static Method getMethod1() { + Block block = new Block( + List.of( + new Declaration( + "a", + Type.INT + ) + ), + List.of( + new Assignment( + new FieldVarAccess( + false, + null, + "a"), + new IntLiteral(10) + ), + new Assignment( + new FieldVarAccess( + true, + null, + "b"), + new New( + Type.REFERENCE("ComplexClass"), + List.of( + new FieldVarAccess( + false, + null, + "x" + ) + ) + + ) + ), + new Assignment( + new FieldVarAccess( + true, + new FieldVarAccess( + false, + null, + "b"), + "x"), + new Binary( + new IntLiteral(10), + Operator.ADD, + new FieldVarAccess( + false, + null, + "a" + ) + ) + ), + new Assignment( + new FieldVarAccess( + true, + new FieldVarAccess( + false, + null, + "b"), + "y"), + new IntLiteral(20) + ), + new Assignment( + new FieldVarAccess( + true, + new FieldVarAccess( + false, + new FieldVarAccess( + false, + null, + "b"), + "c"), + "x"), + new Binary( + new IntLiteral(20), + Operator.ADD, + new FieldVarAccess( + false, + null, + "a" + ) + ) + ), + new IfElse( + new MethodCall( + new FieldVarAccess( + false, + null, + "methodCall"), + List.of() + ), + new Block( + List.of(), + List.of( + new Assignment( + new FieldVarAccess( + true, + new FieldVarAccess( + false, + new MethodCall( + new FieldVarAccess( + false, + new FieldVarAccess( + false, + null, + "b" + ), + "getC" + ), + List.of() + ), + "b"), + "y"), + new FieldVarAccess( + true, + new FieldVarAccess( + false, + null, + "b" + ), + "x" + ) + ) + ) + ), + null + ), + new Return( + new FieldVarAccess( + true, + null, + "b" + ) + ) + ) + + ); + return new Method( + Type.REFERENCE("ComplexClass"), + "initComplexClass", + List.of( + new Parameter( + "x", + Type.INT + ) + ), + block + ); + } + + private static Method getMethod2() { + Block block = new Block( + List.of(), + List.of( + new Return( + new New( + Type.REFERENCE("ComplexClass"), + List.of( + new FieldVarAccess( + false, + null, + "x" + ), + new FieldVarAccess( + false, + null, + "y" + ) + ) + ) + ) + ) + ); + return new Method( + Type.REFERENCE("ComplexClass"), + "init", + List.of( + new Parameter( + "x", + Type.INT + ), + new Parameter( + "y", + Type.INT + ) + ), + block + ); + } + + private static Method getMethod3() { + Block block = new Block( + List.of(), + List.of( + new Return( + new FieldVarAccess( + true, + null, + "x" + ) + ) + ) + ); + return new Method( + Type.INT, + "getX", + List.of( + new Parameter( + "z", + Type.CHAR + ) + ), + block + ); + } + + private static Method getMethod4() { + Block block = new Block( + List.of(), + List.of( + new Return( + new FieldVarAccess( + true, + null, + "c" + ) + ) + ) + ); + return new Method( + Type.REFERENCE("ComplexClass"), + "getC", + List.of(), + block + ); + } + + private static Method getMethod5() { + Block block = new Block( + List.of(), + List.of( + new Return( + new FieldVarAccess( + true, + null, + "x" + ) + ) + ) + ); + return new Method( + Type.INT, + "getX", + List.of(), + block + ); + } + + private static Method getMethod6() { + Block block = new Block( + List.of(), + List.of( + new Return( + new BoolLiteral(false) + ) + ) + ); + return new Method( + Type.BOOL, + "methodCall", + List.of(), + block + ); + } +} diff --git a/src/main/resources/JavaTestfiles/ClassCanBeTyped.java b/src/main/resources/JavaTestfiles/ClassCanBeTyped.java new file mode 100644 index 0000000..7f6b0cf --- /dev/null +++ b/src/main/resources/JavaTestfiles/ClassCanBeTyped.java @@ -0,0 +1,19 @@ + +public class ClassCanBeTyped{ + public int c; + public ClassCanBeTyped d; + public int x; + + public ClassCanBeTyped() { + } + + public ClassCanBeTyped(int x) { + this.x = x; + } + + public ClassCanBeTyped test(int i) { + ClassCanBeTyped a; + a = new ClassCanBeTyped(i); + return a; + } +} \ No newline at end of file diff --git a/src/main/resources/JavaTestfiles/ComplexClass.java b/src/main/resources/JavaTestfiles/ComplexClass.java index e61f30d..f374cee 100644 --- a/src/main/resources/JavaTestfiles/ComplexClass.java +++ b/src/main/resources/JavaTestfiles/ComplexClass.java @@ -4,44 +4,21 @@ public class ComplexClass { int y; ComplexClass b; ComplexClass c; - public ComplexClass(int x) { - this.x = x; - } - public ComplexClass(int x, int y) { - this.x = x; - this.y = y; - } - public ComplexClass initComplexClass(int x) { - int a; - a = 10; - b = new ComplexClass(x); - b.x = 10 + a; - b.y = 20; - b.c.x = 20 + a; - b.c.b.y = b.x; - - return b; - } - public ComplexClass init(int x, int y) { - return new ComplexClass(x, y); - } - public ComplexClass(int x) { - this.x = x; - int i; - b = b.getX().c.getC(); - i = b.getX().c.getX(); - } public ComplexClass() { - this.x = 10; + this.y = 10; + this.x = 2; int i; - for (i = 0; i < (x + 1); i = i + 1) { + for (i = 0; i < (this.y + 1); i = i + 1) { int j; - for (j = 0; j < this.x; j += 1) { + for (j = 0; j < this.y; j += 1) { this.x = this.x * this.x; - break; + if (this.x == 100) { + break; + } } } + this.y = 2; do { this.y = this.y + 1; } while (this.y < 10); @@ -50,12 +27,44 @@ public class ComplexClass { k = 0; for (k = 0; k < 10; k = k + 1) { if (k == 5) { - return; + return this; } } } + public ComplexClass(int x) { + this.b = new ComplexClass(); + this.c = new ComplexClass(); + this.x = x; + this.b.x = 7; + this.b.y = 13; + this.c.x = this.b.getX() * this.b.y * this.b.getX('g'); + this.c.y = 25; + } + + public ComplexClass(int x, int y) { + this.x = x; + this.y = y; + } + + public ComplexClass initComplexClass(int x) { + int a; + a = 10; + this.b = new ComplexClass(x); + this.b.x = 10 + a; + this.b.y = 20; + this.b.c.x = 20 + a; + if (methodCall()) { + this.b.getC().b.y = this.b.x; + } + return this.b; + } + + public ComplexClass init(int x, int y) { + return new ComplexClass(x, y); + } + public ComplexClass(int x, int y, char z) { this.x = x; this.y = y; @@ -66,16 +75,15 @@ public class ComplexClass { } public ComplexClass getC() { - return c; + return this.c; } public int getX() { - return x; + return this.x; } public boolean methodCall() { return false; } - } diff --git a/src/main/resources/TypedAbstractSyntax/TypedAbstractSyntax_ClassWithConstructor.java b/src/main/resources/TypedAbstractSyntax/TypedAbstractSyntax_ClassWithConstructor.java index b7dbc45..49c4cd8 100644 --- a/src/main/resources/TypedAbstractSyntax/TypedAbstractSyntax_ClassWithConstructor.java +++ b/src/main/resources/TypedAbstractSyntax/TypedAbstractSyntax_ClassWithConstructor.java @@ -35,9 +35,10 @@ public class TypedAbstractSyntax_ClassWithConstructor { getConstructors(), null, null, - Type.REFERENCE("ClassWithField") + Type.REFERENCE("ClassWithConstructor") ) - ) + ), + null ); } @@ -203,20 +204,20 @@ public class TypedAbstractSyntax_ClassWithConstructor { Type.INT ) ), - Type.INT + Type.VOID ), - Type.INT + Type.VOID ) ), - Type.INT + Type.VOID ), - Type.INT + Type.VOID ) ); TypedBlock typedBlock = new TypedBlock( typedLocalVariables, typedStatementList, - Type.INT + Type.VOID ); return new TypedConstructor( diff --git a/src/main/resources/TypedAbstractSyntax/TypedAbstractSyntax_ClassWithField.java b/src/main/resources/TypedAbstractSyntax/TypedAbstractSyntax_ClassWithField.java index 9c39652..4abf824 100644 --- a/src/main/resources/TypedAbstractSyntax/TypedAbstractSyntax_ClassWithField.java +++ b/src/main/resources/TypedAbstractSyntax/TypedAbstractSyntax_ClassWithField.java @@ -38,7 +38,8 @@ public class TypedAbstractSyntax_ClassWithField { null, Type.REFERENCE("ClassWithField") ) - ) + ), + null ); } } \ No newline at end of file diff --git a/src/main/resources/TypedAbstractSyntax/TypedAbstractSyntax_ComplexClass.java b/src/main/resources/TypedAbstractSyntax/TypedAbstractSyntax_ComplexClass.java new file mode 100644 index 0000000..4c4832f --- /dev/null +++ b/src/main/resources/TypedAbstractSyntax/TypedAbstractSyntax_ComplexClass.java @@ -0,0 +1,960 @@ +//public class ComplexClass { +// +// int x; +// int y; +// ComplexClass b; +// ComplexClass c; +// +// public ComplexClass() { +// this.y = 10; +// this.x = 2; +// int i; +// for (i = 0; i < (this.y + 1); i = i + 1) { +// int j; +// for (j = 0; j < this.y; j += 1) { +// this.x = this.x * this.x; +// if (this.x == 100) { +// break; +// } +// } +// } +// this.y = 2; +// do { +// this.y = this.y + 1; +// } while (this.y < 10); +// +// int k; +// k = 0; +// for (k = 0; k < 10; k = k + 1) { +// if (k == 5) { +// return this; +// } +// } +// +// } +// +// public ComplexClass(int x) { +// this.b = new ComplexClass(); +// this.c = new ComplexClass(); +// this.x = x; +// this.b.x = 7; +// this.b.y = 13; +// this.c.x = this.b.getX() * this.b.y * this.b.getX('g'); +// this.c.y = 25; +// } +// +// public ComplexClass(int x, int y) { +// this.x = x; +// this.y = y; +// } +// +// public ComplexClass initComplexClass(int x) { +// int a; +// a = 10; +// this.b = new ComplexClass(x); +// this.b.x = 10 + a; +// this.b.y = 20; +// this.b.c.x = 20 + a; +// if (methodCall()) { +// this.b.getC().b.y = this.b.x; +// } +// return this.b; +// } +// +// public ComplexClass init(int x, int y) { +// return new ComplexClass(x, y); +// } +// +// public ComplexClass(int x, int y, char z) { +// this.x = x; +// this.y = y; +// } +// +// public int getX(char z) { +// return this.x; +// } +// +// public ComplexClass getC() { +// return this.c; +// } +// +// public int getX() { +// return this.x; +// } +// +// public boolean methodCall() { +// return false; +// } +// +//} + + +import de.maishai.ast.Operator; +import de.maishai.typedast.Type; +import de.maishai.typedast.typedclass.*; + +import java.util.List; + + +public class TypedAbstractSyntax_ComplexClass { + public static TypedProgram get() { + return new TypedProgram( + getClasses(), + null + ); + } + + private static List getClasses() { + return List.of( + getClass1() + ); + } + + private static TypedClass getClass1() { + return new TypedClass( + "ComplexClass", + getFields(), + getMethods(), + getConstructors(), + null, + null, + Type.REFERENCE("ComplexClass") + ); + } + + private static List getFields() { + return List.of( + new TypedDeclaration("x", Type.INT), + new TypedDeclaration("y", Type.INT), + new TypedDeclaration("b", Type.REFERENCE("ComplexClass")), + new TypedDeclaration("c", Type.REFERENCE("ComplexClass")) + ); + } + + private static List getConstructors() { + return List.of( + getConstructor1(), + getConstructor2(), + getConstructor3(), + getConstructor4() + ); + } + + private static TypedConstructor getConstructor1() { + TypedBlock block = new TypedBlock( + List.of( + new TypedLocalVariable("i", Type.INT), + new TypedLocalVariable("k", Type.INT) + ), + List.of( + new TypedAssignment( + new TypedIntLiteral(10), + new TypedFieldVarAccess( + true, + null, + "y", + Type.INT + ), + Type.INT + ), + new TypedAssignment( + new TypedIntLiteral(2), + new TypedFieldVarAccess( + true, + null, + "x", + Type.INT + ), + Type.INT + ), + new TypedFor( + new TypedAssignment( + new TypedIntLiteral(0), + new TypedFieldVarAccess( + false, + null, + "i", + Type.INT), + Type.INT + ), + new TypedBinary( + new TypedFieldVarAccess( + false, + null, + "i", + Type.INT), + Operator.LT, + new TypedBinary( + new TypedFieldVarAccess( + true, + null, + "y", + Type.INT + ), + Operator.ADD, + new TypedIntLiteral(1), + Type.INT + ), + Type.BOOL + ), + new TypedAssignment( + new TypedBinary( + new TypedFieldVarAccess( + false, + null, + "i", + Type.INT), + Operator.ADD, + new TypedIntLiteral(1), + Type.INT + ), + new TypedFieldVarAccess( + false, + null, + "i", + Type.INT), + Type.INT + ), + new TypedBlock( + List.of( + new TypedLocalVariable( + "j", + Type.INT + ) + ), + List.of( + new TypedFor( + new TypedAssignment( + new TypedIntLiteral(0), + new TypedFieldVarAccess( + false, + null, + "j", + Type.INT), + Type.INT + ), + new TypedBinary( + new TypedFieldVarAccess( + false, + null, + "j", + Type.INT), + Operator.LT, + new TypedFieldVarAccess( + true, + null, + "y", + Type.INT + ), + Type.BOOL + ), + new TypedAssignment( + new TypedBinary( + new TypedIntLiteral(1), + Operator.ADD, + new TypedFieldVarAccess( + false, + null, + "j", + Type.INT + ), + Type.INT + ), + new TypedFieldVarAccess( + false, + null, + "j", + Type.INT + ), + Type.INT + ), + new TypedBlock( + List.of(), + List.of( + new TypedAssignment( + new TypedBinary( + new TypedFieldVarAccess( + true, + null, + "x", + Type.INT + ), + Operator.MUL, + new TypedFieldVarAccess( + true, + null, + "x", + Type.INT + ), + Type.INT + ), + new TypedFieldVarAccess( + true, + null, + "x", + Type.INT + ), + Type.INT + ), + new TypedIfElse( + new TypedBinary( + new TypedFieldVarAccess( + true, + null, + "x", + Type.INT + ), + Operator.EQ, + new TypedIntLiteral(100), + Type.BOOL + ), + new TypedBlock( + List.of(), + List.of( + new TypedBreak() + ) + ), + null, + Type.VOID + ) + ) + ), + Type.VOID + ) + ) + ), + Type.VOID + ) + + ) + ); + return new TypedConstructor( + "ComplexClass", + List.of(), + block + ); + } + + private static TypedConstructor getConstructor2() { + TypedBlock block = new TypedBlock( + List.of(), + List.of( + new TypedAssignment( + new TypedNew( + Type.REFERENCE("ComplexClass"), + List.of() + ), + new TypedFieldVarAccess( + true, + null, + "b", + Type.REFERENCE("ComplexClass") + ), + Type.REFERENCE("ComplexClass") + ), + new TypedAssignment( + new TypedNew( + Type.REFERENCE("ComplexClass"), + List.of() + ), + new TypedFieldVarAccess( + true, + null, + "b", + Type.REFERENCE("ComplexClass") + ), + Type.REFERENCE("ComplexClass") + ), + new TypedAssignment( + new TypedFieldVarAccess( + false, + null, + "x", + Type.INT + ), + new TypedFieldVarAccess( + true, + null, + "x", + Type.INT + ), + Type.INT + ), + new TypedAssignment( + new TypedIntLiteral(7), + new TypedFieldVarAccess( + true, + new TypedFieldVarAccess( + false, + null, + "b", + Type.REFERENCE("ComplexClass") + ), + "x", + Type.INT + ), + Type.INT + ), + new TypedAssignment( + new TypedIntLiteral(13), + new TypedFieldVarAccess( + true, + new TypedFieldVarAccess( + false, + null, + "b", + Type.REFERENCE("ComplexClass") + ), + "y", + Type.INT + ), + Type.INT + ), + new TypedAssignment( + new TypedBinary( + new TypedBinary( + new TypedMethodCall( + new TypedFieldVarAccess( + true, + new TypedFieldVarAccess( + false, + null, + "b", + Type.REFERENCE("ComplexClass") + ), + "getX", + Type.INT + ), + List.of(), + Type.INT + ), + Operator.MUL, + new TypedFieldVarAccess( + true, + new TypedFieldVarAccess( + false, + null, + "b", + Type.REFERENCE("ComplexClass") + ), + "y", + Type.INT + ), + Type.INT + ), + Operator.MUL, + new TypedMethodCall( + new TypedFieldVarAccess( + true, + new TypedFieldVarAccess( + false, + null, + "b", + Type.REFERENCE("ComplexClass") + ), + "getX", + Type.INT + ), + List.of( + new TypedCharLiteral( + 'g', + Type.CHAR + ) + ), + Type.INT + ), + Type.INT + ), + new TypedFieldVarAccess( + true, + new TypedFieldVarAccess( + false, + null, + "c", + Type.REFERENCE("ComplexClass") + ), + "x", + Type.INT + ), + Type.INT + ), + new TypedAssignment( + new TypedIntLiteral(25), + new TypedFieldVarAccess( + true, + new TypedFieldVarAccess( + false, + null, + "c", + Type.REFERENCE("ComplexClass") + ), + "y", + Type.INT + ), + Type.INT + ) + ) + ); + return new TypedConstructor( + "ComplexClass", + List.of( + new TypedParameter( + "x", + Type.INT + ) + ), + block + ); + } + + private static TypedConstructor getConstructor3() { + TypedBlock block = new TypedBlock( + List.of(), + List.of( + new TypedAssignment( + new TypedFieldVarAccess( + false, + null, + "x", + Type.INT + ), + new TypedFieldVarAccess( + true, + null, + "x", + Type.INT + ), + Type.INT + ), + new TypedAssignment( + new TypedFieldVarAccess( + false, + null, + "y", + Type.INT + ), + new TypedFieldVarAccess( + true, + null, + "y", + Type.INT + ), + Type.INT + ) + ) + ); + return new TypedConstructor( + "ComplexClass", + List.of( + new TypedParameter( + "x", + Type.INT + ), + new TypedParameter( + "y", + Type.INT + ) + ), + block + ); + } + + private static TypedConstructor getConstructor4() { + TypedBlock block = new TypedBlock( + List.of(), + List.of( + new TypedAssignment( + new TypedFieldVarAccess( + false, + null, + "x", + Type.INT + ), + new TypedFieldVarAccess( + true, + null, + "x", + Type.INT + ), + Type.INT + ), + new TypedAssignment( + new TypedFieldVarAccess( + false, + null, + "y", + Type.INT + ), + new TypedFieldVarAccess( + true, + null, + "y", + Type.INT + ), + Type.INT + ) + ) + ); + return new TypedConstructor( + "ComplexClass", + List.of( + new TypedParameter( + "x", + Type.INT + ), + new TypedParameter( + "y", + Type.INT + ), + new TypedParameter( + "z", + Type.CHAR + ) + ), + block + ); + } + + private static List getMethods() { + return List.of( + getMethod1(), + getMethod2(), + getMethod3(), + getMethod4(), + getMethod5(), + getMethod6() + ); + } + + private static TypedMethod getMethod1() { + TypedBlock block = new TypedBlock( + List.of( + new TypedLocalVariable("a", Type.INT) + ), + List.of( + new TypedAssignment( + new TypedIntLiteral(10), + new TypedFieldVarAccess( + false, + null, + "a", + Type.REFERENCE("ComplexClass") + ), + Type.INT + ), + new TypedAssignment( + new TypedNew( + Type.REFERENCE("ComplexClass"), + List.of( + new TypedFieldVarAccess( + false, + null, + "x", + Type.INT + ) + ) + ), + new TypedFieldVarAccess( + true, + null, + "b", + Type.REFERENCE("ComplexClass") + ), + Type.REFERENCE("ComplexClass") + ), + new TypedAssignment( + new TypedBinary( + new TypedIntLiteral(10), + Operator.ADD, + new TypedFieldVarAccess( + false, + null, + "a", + Type.INT + ), + Type.INT + ), + new TypedFieldVarAccess( + true, + new TypedFieldVarAccess( + false, + null, + "b", + Type.REFERENCE("ComplexClass") + ), + "x", + Type.INT + ), + Type.INT + ), + new TypedAssignment( + new TypedIntLiteral(20), + new TypedFieldVarAccess( + true, + new TypedFieldVarAccess( + false, + null, + "b", + Type.REFERENCE("ComplexClass") + ), + "y", + Type.INT + ), + Type.INT + ), + new TypedAssignment( + new TypedBinary( + new TypedIntLiteral(20), + Operator.ADD, + new TypedFieldVarAccess( + false, + null, + "a", + Type.INT + ), + Type.INT + ), + new TypedFieldVarAccess( + true, + new TypedFieldVarAccess( + false, + new TypedFieldVarAccess( + false, + null, + "b", + Type.REFERENCE("ComplexClass") + ), + "c", + Type.REFERENCE("ComplexClass") + ), + "x", + Type.INT + ), + Type.INT + ), + new TypedIfElse( + new TypedMethodCall( + new TypedFieldVarAccess( + false, + null, + "methodCall", + Type.BOOL + ), + List.of(), + Type.BOOL + ), + new TypedBlock( + List.of(), + List.of( + new TypedAssignment( + new TypedFieldVarAccess( + true, + new TypedFieldVarAccess( + false, + null, + "b", + Type.REFERENCE("ComplexClass") + ), + "x", + Type.INT + ), + new TypedFieldVarAccess( + true, + new TypedFieldVarAccess( + false, + new TypedMethodCall( + new TypedFieldVarAccess( + false, + new TypedFieldVarAccess( + false, + null, + "b", + Type.REFERENCE("ComplexClass") + ), + "getC", + Type.REFERENCE("ComplexClass") + ), + List.of(), + Type.REFERENCE("ComplexClass") + ), + "b", + Type.REFERENCE("ComplexClass") + ), + "y", + Type.INT + ), + Type.INT + ) + ) + ), + null, + Type.VOID + ), + new TypedReturn( + new TypedFieldVarAccess( + true, + null, + "b", + Type.REFERENCE("ComplexClass") + ), + Type.REFERENCE("ComplexClass") + ) + ) + ); + return new TypedMethod( + "initComplexClass", + Type.REFERENCE("ComplexClass"), + List.of( + new TypedParameter( + "x", + Type.INT + ) + ), + List.of(), + block + ); + } + + private static TypedMethod getMethod2() { + TypedBlock block = new TypedBlock( + List.of(), + List.of( + new TypedReturn( + new TypedNew( + Type.REFERENCE("ComplexClass"), + List.of( + new TypedFieldVarAccess( + false, + null, + "x", + Type.INT + ), + new TypedFieldVarAccess( + false, + null, + "y", + Type.INT + ) + ) + ), + Type.REFERENCE("ComplexClass") + ) + ) + ); + return new TypedMethod( + "init", + Type.REFERENCE("ComplexClass"), + List.of( + new TypedParameter( + "x", + Type.INT + ), + new TypedParameter( + "y", + Type.INT + ) + ), + List.of(), + block + ); + } + + private static TypedMethod getMethod3() { + TypedBlock block = new TypedBlock( + List.of(), + List.of( + new TypedReturn( + new TypedFieldVarAccess( + true, + null, + "x", + Type.INT + ), + Type.INT + ) + ) + ); + return new TypedMethod( + "getX", + Type.INT, + List.of( + new TypedParameter( + "z", + Type.CHAR + ) + ), + List.of(), + block + ); + } + + private static TypedMethod getMethod4() { + TypedBlock block = new TypedBlock( + List.of(), + List.of( + new TypedReturn( + new TypedFieldVarAccess( + true, + null, + "c", + Type.REFERENCE("ComplexClass") + ), + Type.REFERENCE("ComplexClass") + ) + ) + ); + return new TypedMethod( + "getC", + Type.REFERENCE("ComplexClass"), + List.of(), + List.of(), + block + ); + } + + private static TypedMethod getMethod5() { + TypedBlock block = new TypedBlock( + List.of(), + List.of( + new TypedReturn( + new TypedFieldVarAccess( + true, + null, + "x", + Type.INT + ), + Type.INT + ) + ) + ); + return new TypedMethod( + "getX", + Type.INT, + List.of(), + List.of(), + block + ); + } + + private static TypedMethod getMethod6() { + TypedBlock block = new TypedBlock( + List.of(), + List.of( + new TypedReturn( + new TypedBoolLiteral( + false, + Type.BOOL + ), + Type.BOOL + ) + ) + ); + return new TypedMethod( + "methodCall", + Type.BOOL, + List.of(), + List.of(), + block + ); + } +} diff --git a/src/main/resources/TypedAbstractSyntax/TypedAbstractSyntax_PublicClass.java b/src/main/resources/TypedAbstractSyntax/TypedAbstractSyntax_PublicClass.java index dba4b7e..79541a2 100644 --- a/src/main/resources/TypedAbstractSyntax/TypedAbstractSyntax_PublicClass.java +++ b/src/main/resources/TypedAbstractSyntax/TypedAbstractSyntax_PublicClass.java @@ -31,7 +31,8 @@ public class TypedAbstractSyntax_PublicClass { null, Type.REFERENCE("PublicClass") ) - ) + ), + null ); } } \ No newline at end of file diff --git a/src/test/java/CodegeneratorTests.java b/src/test/java/CodegeneratorTests.java new file mode 100644 index 0000000..cc580ad --- /dev/null +++ b/src/test/java/CodegeneratorTests.java @@ -0,0 +1,16 @@ +import de.maishai.Compiler; +import de.maishai.ast.records.Program; +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class CodegeneratorTests { + +// @Test +// public void testPublicClass() { +// byte[] resultBytecode = Compiler.generateByteCodeArrayFromTypedAst(); +// assertEquals(AbstractSyntax_PublicClass.get(), resultBytecode); +// } +} diff --git a/src/test/java/ScannerParserTests.java b/src/test/java/ScannerParserTests.java index 4e27183..a490eca 100644 --- a/src/test/java/ScannerParserTests.java +++ b/src/test/java/ScannerParserTests.java @@ -59,6 +59,6 @@ public class ScannerParserTests { @Test public void testComplexClass() { Program resultAst = Compiler.generateASTFromFile(List.of("src/main/resources/JavaTestfiles/ComplexClass.java")); - assertEquals(AbstractSyntax_ClassWithConstructorAndMethodCall.get(), resultAst); + assertEquals(TypedAbstractSyntax_ComplexClass.get(), resultAst); } } diff --git a/src/test/java/TypingTests.java b/src/test/java/TypingTests.java index d81e9dd..6c2cda3 100644 --- a/src/test/java/TypingTests.java +++ b/src/test/java/TypingTests.java @@ -23,4 +23,10 @@ public class TypingTests { TypedProgram resultTypedAst = Compiler.generateTypedASTFromAst(AbstractSyntax_ClassWithConstructor.get()); assertEquals(TypedAbstractSyntax_ClassWithConstructor.get(), resultTypedAst); } + + @Test + public void testComplexClass() { + TypedProgram resultTypedAst = Compiler.generateTypedASTFromAst(AbstractSyntax_ComplexClass.get()); + assertEquals(TypedAbstractSyntax_ComplexClass.get(), resultTypedAst); + } }