From 9f084a79bbed56ba9f3fc39ca3a25b88b13b8c4c Mon Sep 17 00:00:00 2001 From: 404Simon Date: Tue, 14 May 2024 00:02:47 +0200 Subject: [PATCH 01/17] refactor and make typedFieldVarAccess Work --- .../de/maishai/typedast/ClassContext.java | 6 +- .../de/maishai/typedast/MethodContext.java | 4 +- .../typedast/typedclass/TypedAssignment.java | 16 +++- .../typedast/typedclass/TypedConstructor.java | 3 + .../typedclass/TypedFieldVarAccess.java | 9 ++- .../JavaTestfiles/ClassCanBeTyped.java | 81 ++----------------- 6 files changed, 36 insertions(+), 83 deletions(-) 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/MethodContext.java b/src/main/java/de/maishai/typedast/MethodContext.java index b3b0832..3d7d00b 100644 --- a/src/main/java/de/maishai/typedast/MethodContext.java +++ b/src/main/java/de/maishai/typedast/MethodContext.java @@ -28,7 +28,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); } @@ -58,6 +58,7 @@ public class MethodContext { } else { mv.visitVarInsn(Opcodes.ILOAD, localVariable.index); } + System.out.println("Pushed " + variableIndex.get(varName) + " to stack"); } public void popStack() { @@ -66,6 +67,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 cc8992e..720050b 100644 --- a/src/main/java/de/maishai/typedast/typedclass/TypedAssignment.java +++ b/src/main/java/de/maishai/typedast/typedclass/TypedAssignment.java @@ -63,9 +63,19 @@ public class TypedAssignment implements TypedStatement { @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()); + ctx.pushStack("this"); + // load location recursively on stack + location.codeGen(ctx); + + // put value on stack (WIP!!) + ctx.pushStack("x"); + + //save value in field + 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()); } } diff --git a/src/main/java/de/maishai/typedast/typedclass/TypedConstructor.java b/src/main/java/de/maishai/typedast/typedclass/TypedConstructor.java index 7c53585..8867511 100644 --- a/src/main/java/de/maishai/typedast/typedclass/TypedConstructor.java +++ b/src/main/java/de/maishai/typedast/typedclass/TypedConstructor.java @@ -77,11 +77,14 @@ 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); + System.out.println("Visiting method: " + "" + CodeGenUtils.generateDescriptor(typedParameters, 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/TypedFieldVarAccess.java b/src/main/java/de/maishai/typedast/typedclass/TypedFieldVarAccess.java index 621ec43..8eb8ede 100644 --- a/src/main/java/de/maishai/typedast/typedclass/TypedFieldVarAccess.java +++ b/src/main/java/de/maishai/typedast/typedclass/TypedFieldVarAccess.java @@ -7,6 +7,7 @@ import de.maishai.typedast.Type; import lombok.Data; import lombok.NoArgsConstructor; import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; import java.util.Map; @@ -76,6 +77,12 @@ public class TypedFieldVarAccess implements TypedExpression { @Override public void codeGen(MethodContext ctx) { - + if (recursiveOwnerChain != null) { + recursiveOwnerChain.codeGen(ctx); + } + if (!field) { + ctx.getMv().visitFieldInsn(Opcodes.GETFIELD, ctx.getClassContext().getName(), name, type.getDescriptor()); + System.out.println("GETFIELD: " + ctx.getClassContext().getName() + " " + name + " " + type.getDescriptor()); + } } } diff --git a/src/main/resources/JavaTestfiles/ClassCanBeTyped.java b/src/main/resources/JavaTestfiles/ClassCanBeTyped.java index b4d9fd9..4c399fe 100644 --- a/src/main/resources/JavaTestfiles/ClassCanBeTyped.java +++ b/src/main/resources/JavaTestfiles/ClassCanBeTyped.java @@ -1,81 +1,10 @@ public class ClassCanBeTyped { + public ClassCanBeTyped c; + public int x; - int x; - int y; - ClassCanBeTyped b; - ClassCanBeTyped c; public ClassCanBeTyped(int x) { - this.x = x; + this.c.x = x; } - public ClassCanBeTyped(int x, int y) { - this.x = x; - this.y = y; - } - public ClassCanBeTyped initClassCanBeTyped(int x) { - int a; - a = 10; - b = new ClassCanBeTyped(x); - b.x = 10 + a; - b.y = 20; - b.c.x = 20 + a; - b.c.b.y = b.x; - - return b; - } - public ClassCanBeTyped init(int x, int y) { - return new ClassCanBeTyped(x, y); - } - public ClassCanBeTyped(int x) { - this.x = x; - int i; - b = b.getX().c.getC(); - i = b.getX().c.getX(); - } - - public ClassCanBeTyped() { - this.x = 10; - int i; - for (i = 0; i < (x + 1); i = i + 1) { - int j; - for (j = 0; j < this.x; j += 1) { - this.x = this.x * this.x; - break; - } - } - 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; - } - } - - } - - public ClassCanBeTyped(int x, int y, char z) { - this.x = x; - this.y = y; - } - - public int getX(char z) { - return this.x; - } - - public ClassCanBeTyped getC() { - return c; - } - - public int getX() { - return x; - } - - public boolean methodCall() { - return false; - } - - } + + From 2fb9ecd668f83ac2289cc0e32fe0b079f56c8e55 Mon Sep 17 00:00:00 2001 From: 404Simon Date: Tue, 14 May 2024 00:06:59 +0200 Subject: [PATCH 02/17] pop that stack --- .../java/de/maishai/typedast/typedclass/TypedAssignment.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/de/maishai/typedast/typedclass/TypedAssignment.java b/src/main/java/de/maishai/typedast/typedclass/TypedAssignment.java index 720050b..fa46c0b 100644 --- a/src/main/java/de/maishai/typedast/typedclass/TypedAssignment.java +++ b/src/main/java/de/maishai/typedast/typedclass/TypedAssignment.java @@ -76,6 +76,8 @@ public class TypedAssignment implements TypedStatement { receiver = location.getRecursiveOwnerChain().getType().getReference(); } ctx.getMv().visitFieldInsn(Opcodes.PUTFIELD, receiver, location.getName(), value.getType().getDescriptor()); + ctx.popStack(); + ctx.popStack(); System.out.println("PUTFIELD: " + receiver + " " + location.getName() + " " + value.getType().getDescriptor()); } } From 9a7d296ecc421603ff48542c329dbadd3ed45ec6 Mon Sep 17 00:00:00 2001 From: 404Simon Date: Tue, 14 May 2024 10:05:07 +0200 Subject: [PATCH 03/17] make most expressions work --- .../de/maishai/typedast/MethodContext.java | 21 ++++++++++++------- .../typedast/typedclass/TypedAssignment.java | 5 ++++- .../typedast/typedclass/TypedBinary.java | 13 +++++++++++- .../typedast/typedclass/TypedBoolLiteral.java | 1 + .../typedast/typedclass/TypedCharLiteral.java | 1 + .../typedclass/TypedFieldVarAccess.java | 5 +++++ .../typedast/typedclass/TypedIntLiteral.java | 1 + .../typedast/typedclass/TypedUnary.java | 1 + .../JavaTestfiles/ClassCanBeTyped.java | 6 ++++-- 9 files changed, 43 insertions(+), 11 deletions(-) diff --git a/src/main/java/de/maishai/typedast/MethodContext.java b/src/main/java/de/maishai/typedast/MethodContext.java index 3d7d00b..c8aba5c 100644 --- a/src/main/java/de/maishai/typedast/MethodContext.java +++ b/src/main/java/de/maishai/typedast/MethodContext.java @@ -1,5 +1,6 @@ package de.maishai.typedast; +import de.maishai.VariableGenerator; import lombok.*; import org.objectweb.asm.Label; import org.objectweb.asm.MethodVisitor; @@ -7,11 +8,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; @@ -39,12 +41,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) { @@ -61,6 +60,14 @@ public class MethodContext { System.out.println("Pushed " + variableIndex.get(varName) + " to stack"); } + public void pushInstantToStack () { + stack.push(localVarIndex); + if (stack.size() > maxStack) { + maxStack = stack.size(); + } + System.out.println("Pushed instant to stack"); + } + public void popStack() { stack.pop(); } diff --git a/src/main/java/de/maishai/typedast/typedclass/TypedAssignment.java b/src/main/java/de/maishai/typedast/typedclass/TypedAssignment.java index fa46c0b..a13f9a5 100644 --- a/src/main/java/de/maishai/typedast/typedclass/TypedAssignment.java +++ b/src/main/java/de/maishai/typedast/typedclass/TypedAssignment.java @@ -64,11 +64,14 @@ public class TypedAssignment implements TypedStatement { @Override public void codeGen(MethodContext ctx) { ctx.pushStack("this"); + System.out.println("left: " + location); + System.out.println("right: " + value); // load location recursively on stack location.codeGen(ctx); // put value on stack (WIP!!) - ctx.pushStack("x"); + //ctx.pushStack("x"); + value.codeGen(ctx); //save value in field String receiver = ctx.getClassContext().getName(); diff --git a/src/main/java/de/maishai/typedast/typedclass/TypedBinary.java b/src/main/java/de/maishai/typedast/typedclass/TypedBinary.java index 5839665..3a2d459 100644 --- a/src/main/java/de/maishai/typedast/typedclass/TypedBinary.java +++ b/src/main/java/de/maishai/typedast/typedclass/TypedBinary.java @@ -8,6 +8,7 @@ import de.maishai.typedast.Type; import lombok.Data; import lombok.NoArgsConstructor; import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; import java.util.Map; @@ -68,6 +69,16 @@ public class TypedBinary implements TypedExpression { @Override public void codeGen(MethodContext ctx) { - + 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); + } + //TODO: implement other operators + ctx.popStack(); } } diff --git a/src/main/java/de/maishai/typedast/typedclass/TypedBoolLiteral.java b/src/main/java/de/maishai/typedast/typedclass/TypedBoolLiteral.java index 27a1fd4..a7016d0 100644 --- a/src/main/java/de/maishai/typedast/typedclass/TypedBoolLiteral.java +++ b/src/main/java/de/maishai/typedast/typedclass/TypedBoolLiteral.java @@ -42,5 +42,6 @@ public class TypedBoolLiteral implements TypedExpression { }else{ ctx.getMv().visitInsn(Opcodes.ICONST_0); } + ctx.pushInstantToStack(); } } diff --git a/src/main/java/de/maishai/typedast/typedclass/TypedCharLiteral.java b/src/main/java/de/maishai/typedast/typedclass/TypedCharLiteral.java index bad3332..5cd2cb9 100644 --- a/src/main/java/de/maishai/typedast/typedclass/TypedCharLiteral.java +++ b/src/main/java/de/maishai/typedast/typedclass/TypedCharLiteral.java @@ -34,5 +34,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/TypedFieldVarAccess.java b/src/main/java/de/maishai/typedast/typedclass/TypedFieldVarAccess.java index 8eb8ede..9bfcabb 100644 --- a/src/main/java/de/maishai/typedast/typedclass/TypedFieldVarAccess.java +++ b/src/main/java/de/maishai/typedast/typedclass/TypedFieldVarAccess.java @@ -77,6 +77,11 @@ public class TypedFieldVarAccess implements TypedExpression { @Override public void codeGen(MethodContext ctx) { + if (!field && recursiveOwnerChain == null && ctx.getLocalVar(name).isPresent() && ctx.getLocalVar(name).get().type().equals(type)) { + // load local variable + ctx.pushStack(name); + return; + } if (recursiveOwnerChain != null) { recursiveOwnerChain.codeGen(ctx); } diff --git a/src/main/java/de/maishai/typedast/typedclass/TypedIntLiteral.java b/src/main/java/de/maishai/typedast/typedclass/TypedIntLiteral.java index b17c149..175a7b9 100644 --- a/src/main/java/de/maishai/typedast/typedclass/TypedIntLiteral.java +++ b/src/main/java/de/maishai/typedast/typedclass/TypedIntLiteral.java @@ -42,5 +42,6 @@ public class TypedIntLiteral implements TypedExpression { @Override public void codeGen(MethodContext ctx) { ctx.getMv().visitLdcInsn(value); + ctx.pushInstantToStack(); } } diff --git a/src/main/java/de/maishai/typedast/typedclass/TypedUnary.java b/src/main/java/de/maishai/typedast/typedclass/TypedUnary.java index 14cefea..8071018 100644 --- a/src/main/java/de/maishai/typedast/typedclass/TypedUnary.java +++ b/src/main/java/de/maishai/typedast/typedclass/TypedUnary.java @@ -26,6 +26,7 @@ public class TypedUnary implements TypedExpression { public void convertToTypedUnary(TypedClass clas, Unary unTypedUnary) { op = unTypedUnary.op(); right = convertExpression(clas, unTypedUnary.right()); + type = right.getType(); } @Override diff --git a/src/main/resources/JavaTestfiles/ClassCanBeTyped.java b/src/main/resources/JavaTestfiles/ClassCanBeTyped.java index 4c399fe..b5d0b60 100644 --- a/src/main/resources/JavaTestfiles/ClassCanBeTyped.java +++ b/src/main/resources/JavaTestfiles/ClassCanBeTyped.java @@ -1,9 +1,11 @@ public class ClassCanBeTyped { public ClassCanBeTyped c; public int x; + public boolean y; - public ClassCanBeTyped(int x) { - this.c.x = x; + public ClassCanBeTyped(int x, boolean y) { + this.c.x = 2 * x; + this.y = !y; } } From 69548745c244d3bb36376e4e84d77f518a01b299 Mon Sep 17 00:00:00 2001 From: 404Simon Date: Tue, 14 May 2024 12:25:15 +0200 Subject: [PATCH 04/17] more binary operator support --- .../de/maishai/typedast/MethodContext.java | 1 - .../typedast/typedclass/TypedBinary.java | 66 ++++++++++++++++--- .../typedast/typedclass/TypedReturn.java | 1 + .../JavaTestfiles/ClassCanBeTyped.java | 6 +- 4 files changed, 62 insertions(+), 12 deletions(-) diff --git a/src/main/java/de/maishai/typedast/MethodContext.java b/src/main/java/de/maishai/typedast/MethodContext.java index c8aba5c..db66b0b 100644 --- a/src/main/java/de/maishai/typedast/MethodContext.java +++ b/src/main/java/de/maishai/typedast/MethodContext.java @@ -1,6 +1,5 @@ package de.maishai.typedast; -import de.maishai.VariableGenerator; import lombok.*; import org.objectweb.asm.Label; import org.objectweb.asm.MethodVisitor; diff --git a/src/main/java/de/maishai/typedast/typedclass/TypedBinary.java b/src/main/java/de/maishai/typedast/typedclass/TypedBinary.java index 3a2d459..2aa1270 100644 --- a/src/main/java/de/maishai/typedast/typedclass/TypedBinary.java +++ b/src/main/java/de/maishai/typedast/typedclass/TypedBinary.java @@ -7,6 +7,7 @@ import de.maishai.typedast.TypedExpression; import de.maishai.typedast.Type; import lombok.Data; import lombok.NoArgsConstructor; +import org.objectweb.asm.Label; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; @@ -69,14 +70,63 @@ public class TypedBinary implements TypedExpression { @Override public void codeGen(MethodContext ctx) { - 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); + 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 { + 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); + } } //TODO: implement other operators ctx.popStack(); diff --git a/src/main/java/de/maishai/typedast/typedclass/TypedReturn.java b/src/main/java/de/maishai/typedast/typedclass/TypedReturn.java index 7da3e43..d354b7b 100644 --- a/src/main/java/de/maishai/typedast/typedclass/TypedReturn.java +++ b/src/main/java/de/maishai/typedast/typedclass/TypedReturn.java @@ -51,6 +51,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/resources/JavaTestfiles/ClassCanBeTyped.java b/src/main/resources/JavaTestfiles/ClassCanBeTyped.java index b5d0b60..d02fcc5 100644 --- a/src/main/resources/JavaTestfiles/ClassCanBeTyped.java +++ b/src/main/resources/JavaTestfiles/ClassCanBeTyped.java @@ -3,9 +3,9 @@ public class ClassCanBeTyped { public int x; public boolean y; - public ClassCanBeTyped(int x, boolean y) { - this.c.x = 2 * x; - this.y = !y; + + public boolean test(boolean b, boolean c) { + return b == c; } } From 8cdbf7a23b94de9a8ee6611b56e4c48806934bbd Mon Sep 17 00:00:00 2001 From: 404Simon Date: Tue, 14 May 2024 14:27:55 +0200 Subject: [PATCH 05/17] all binary operator supported --- .../typedast/typedclass/TypedBinary.java | 75 +++++++++++++++++++ .../JavaTestfiles/ClassCanBeTyped.java | 2 +- 2 files changed, 76 insertions(+), 1 deletion(-) diff --git a/src/main/java/de/maishai/typedast/typedclass/TypedBinary.java b/src/main/java/de/maishai/typedast/typedclass/TypedBinary.java index 2aa1270..0546da8 100644 --- a/src/main/java/de/maishai/typedast/typedclass/TypedBinary.java +++ b/src/main/java/de/maishai/typedast/typedclass/TypedBinary.java @@ -111,6 +111,81 @@ public class TypedBinary implements TypedExpression { 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); diff --git a/src/main/resources/JavaTestfiles/ClassCanBeTyped.java b/src/main/resources/JavaTestfiles/ClassCanBeTyped.java index d02fcc5..85a8236 100644 --- a/src/main/resources/JavaTestfiles/ClassCanBeTyped.java +++ b/src/main/resources/JavaTestfiles/ClassCanBeTyped.java @@ -5,7 +5,7 @@ public class ClassCanBeTyped { public boolean test(boolean b, boolean c) { - return b == c; + return b || c; } } From 21aa8b1a2bcc69e15a5912bf4e9587163865ed19 Mon Sep 17 00:00:00 2001 From: 404Simon Date: Tue, 14 May 2024 14:55:36 +0200 Subject: [PATCH 06/17] register block vars --- .../de/maishai/typedast/typedclass/TypedBinary.java | 1 - .../de/maishai/typedast/typedclass/TypedBlock.java | 2 +- src/main/resources/JavaTestfiles/ClassCanBeTyped.java | 11 ++++++++--- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/main/java/de/maishai/typedast/typedclass/TypedBinary.java b/src/main/java/de/maishai/typedast/typedclass/TypedBinary.java index 0546da8..880225e 100644 --- a/src/main/java/de/maishai/typedast/typedclass/TypedBinary.java +++ b/src/main/java/de/maishai/typedast/typedclass/TypedBinary.java @@ -203,7 +203,6 @@ public class TypedBinary implements TypedExpression { ctx.getMv().visitInsn(Opcodes.IMUL); } } - //TODO: implement other operators 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 f234391..0d08a71 100644 --- a/src/main/java/de/maishai/typedast/typedclass/TypedBlock.java +++ b/src/main/java/de/maishai/typedast/typedclass/TypedBlock.java @@ -119,7 +119,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/resources/JavaTestfiles/ClassCanBeTyped.java b/src/main/resources/JavaTestfiles/ClassCanBeTyped.java index 85a8236..4cae684 100644 --- a/src/main/resources/JavaTestfiles/ClassCanBeTyped.java +++ b/src/main/resources/JavaTestfiles/ClassCanBeTyped.java @@ -1,11 +1,16 @@ public class ClassCanBeTyped { - public ClassCanBeTyped c; + public ClassCanBeTyped p; public int x; public boolean y; - public boolean test(boolean b, boolean c) { - return b || c; + public int test(boolean b, boolean c) { + int y; + y = 0; + if (b && c) { + y = 12; + } + return y; } } From a3d7c1da7e0fba697bc862e0c232e5812aae82b8 Mon Sep 17 00:00:00 2001 From: 404Simon Date: Tue, 14 May 2024 15:51:01 +0200 Subject: [PATCH 07/17] add typecheck --- .../java/de/maishai/typedast/typedclass/TypedAssignment.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/de/maishai/typedast/typedclass/TypedAssignment.java b/src/main/java/de/maishai/typedast/typedclass/TypedAssignment.java index a13f9a5..63d8e08 100644 --- a/src/main/java/de/maishai/typedast/typedclass/TypedAssignment.java +++ b/src/main/java/de/maishai/typedast/typedclass/TypedAssignment.java @@ -27,6 +27,7 @@ public class TypedAssignment implements TypedStatement { public void convertToTypedAssignment(TypedClass clas, Assignment untyped) { value = convertExpression(clas, untyped.value()); location = new TypedFieldVarAccess(clas, untyped.location()); + location.typeCheck(clas); } @Override From 017014c0ce0992fe925a287914f0279b3228581e Mon Sep 17 00:00:00 2001 From: 404Simon Date: Tue, 14 May 2024 23:57:17 +0200 Subject: [PATCH 08/17] make new work --- .../java/de/maishai/ExpressionGenerator.java | 8 ++-- .../de/maishai/typedast/CodeGenUtils.java | 4 +- .../de/maishai/typedast/MethodContext.java | 9 +++- .../typedast/typedclass/TypedAssignment.java | 47 +++++++++++++------ .../typedast/typedclass/TypedConstructor.java | 4 +- .../typedclass/TypedFieldVarAccess.java | 17 +++---- .../typedast/typedclass/TypedIntLiteral.java | 12 ++++- .../typedast/typedclass/TypedMethod.java | 2 +- .../maishai/typedast/typedclass/TypedNew.java | 16 +++++++ .../JavaTestfiles/ClassCanBeTyped.java | 26 +++++----- 10 files changed, 100 insertions(+), 45 deletions(-) diff --git a/src/main/java/de/maishai/ExpressionGenerator.java b/src/main/java/de/maishai/ExpressionGenerator.java index d5d87cb..3701aec 100644 --- a/src/main/java/de/maishai/ExpressionGenerator.java +++ b/src/main/java/de/maishai/ExpressionGenerator.java @@ -106,9 +106,11 @@ public class ExpressionGenerator extends DecafBaseVisitor { public Expression visitNew(DecafParser.NewContext ctx) { Type type = ASTGenerator.getType(ctx.type()); List args = new ArrayList<>(); - for (var expr : ctx.args().expr()) { - Expression astExpr = expr.accept(this); - args.add(astExpr); + if (ctx.args() != null) { + for (var expr : ctx.args().expr()) { + Expression astExpr = expr.accept(this); + args.add(astExpr); + } } return new New(type, args); } 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/MethodContext.java b/src/main/java/de/maishai/typedast/MethodContext.java index db66b0b..f252656 100644 --- a/src/main/java/de/maishai/typedast/MethodContext.java +++ b/src/main/java/de/maishai/typedast/MethodContext.java @@ -59,12 +59,19 @@ public class MethodContext { 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(); } - System.out.println("Pushed instant to stack"); } public void popStack() { diff --git a/src/main/java/de/maishai/typedast/typedclass/TypedAssignment.java b/src/main/java/de/maishai/typedast/typedclass/TypedAssignment.java index 63d8e08..cc223fc 100644 --- a/src/main/java/de/maishai/typedast/typedclass/TypedAssignment.java +++ b/src/main/java/de/maishai/typedast/typedclass/TypedAssignment.java @@ -64,24 +64,41 @@ public class TypedAssignment implements TypedStatement { @Override public void codeGen(MethodContext ctx) { - ctx.pushStack("this"); - System.out.println("left: " + location); - System.out.println("right: " + value); - // load location recursively on stack - location.codeGen(ctx); + if(value instanceof TypedNew) { + value.codeGen(ctx); + getOwnerChain(ctx); + } else { + ctx.pushStack("this"); + getOwnerChain(ctx); + value.codeGen(ctx); + } - // put value on stack (WIP!!) - //ctx.pushStack("x"); - value.codeGen(ctx); //save value in field - String receiver = ctx.getClassContext().getName(); - if (location.getRecursiveOwnerChain() != null) { - receiver = location.getRecursiveOwnerChain().getType().getReference(); + 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(); } - ctx.getMv().visitFieldInsn(Opcodes.PUTFIELD, receiver, location.getName(), value.getType().getDescriptor()); - ctx.popStack(); - ctx.popStack(); - System.out.println("PUTFIELD: " + receiver + " " + location.getName() + " " + value.getType().getDescriptor()); } } diff --git a/src/main/java/de/maishai/typedast/typedclass/TypedConstructor.java b/src/main/java/de/maishai/typedast/typedclass/TypedConstructor.java index 8867511..6cd9d96 100644 --- a/src/main/java/de/maishai/typedast/typedclass/TypedConstructor.java +++ b/src/main/java/de/maishai/typedast/typedclass/TypedConstructor.java @@ -76,8 +76,8 @@ 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); - System.out.println("Visiting method: " + "" + CodeGenUtils.generateDescriptor(typedParameters, Type.VOID)); + 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(); diff --git a/src/main/java/de/maishai/typedast/typedclass/TypedFieldVarAccess.java b/src/main/java/de/maishai/typedast/typedclass/TypedFieldVarAccess.java index 9bfcabb..cb6d6a7 100644 --- a/src/main/java/de/maishai/typedast/typedclass/TypedFieldVarAccess.java +++ b/src/main/java/de/maishai/typedast/typedclass/TypedFieldVarAccess.java @@ -77,17 +77,18 @@ public class TypedFieldVarAccess implements TypedExpression { @Override public void codeGen(MethodContext ctx) { - if (!field && recursiveOwnerChain == null && ctx.getLocalVar(name).isPresent() && ctx.getLocalVar(name).get().type().equals(type)) { - // load local variable - ctx.pushStack(name); - return; - } if (recursiveOwnerChain != null) { recursiveOwnerChain.codeGen(ctx); } - if (!field) { - ctx.getMv().visitFieldInsn(Opcodes.GETFIELD, ctx.getClassContext().getName(), name, type.getDescriptor()); - System.out.println("GETFIELD: " + ctx.getClassContext().getName() + " " + name + " " + type.getDescriptor()); + 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/TypedIntLiteral.java b/src/main/java/de/maishai/typedast/typedclass/TypedIntLiteral.java index 175a7b9..6066e76 100644 --- a/src/main/java/de/maishai/typedast/typedclass/TypedIntLiteral.java +++ b/src/main/java/de/maishai/typedast/typedclass/TypedIntLiteral.java @@ -9,6 +9,7 @@ import lombok.AllArgsConstructor; import lombok.Data; import lombok.RequiredArgsConstructor; import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; import java.util.Map; @@ -41,7 +42,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 d778edc..7c937df 100644 --- a/src/main/java/de/maishai/typedast/typedclass/TypedMethod.java +++ b/src/main/java/de/maishai/typedast/typedclass/TypedMethod.java @@ -110,7 +110,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/TypedNew.java b/src/main/java/de/maishai/typedast/typedclass/TypedNew.java index e06b450..b2ba299 100644 --- a/src/main/java/de/maishai/typedast/typedclass/TypedNew.java +++ b/src/main/java/de/maishai/typedast/typedclass/TypedNew.java @@ -5,6 +5,7 @@ import de.maishai.ast.records.New; import de.maishai.typedast.*; import lombok.Data; import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; import java.util.ArrayList; import java.util.List; @@ -50,6 +51,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/resources/JavaTestfiles/ClassCanBeTyped.java b/src/main/resources/JavaTestfiles/ClassCanBeTyped.java index 4cae684..7f6b0cf 100644 --- a/src/main/resources/JavaTestfiles/ClassCanBeTyped.java +++ b/src/main/resources/JavaTestfiles/ClassCanBeTyped.java @@ -1,17 +1,19 @@ -public class ClassCanBeTyped { - public ClassCanBeTyped p; + +public class ClassCanBeTyped{ + public int c; + public ClassCanBeTyped d; public int x; - public boolean y; - - public int test(boolean b, boolean c) { - int y; - y = 0; - if (b && c) { - y = 12; - } - return y; + 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 From aaa8a27ff914636e093ca3924d4514d279640624 Mon Sep 17 00:00:00 2001 From: ahmad Date: Wed, 15 May 2024 16:42:09 +0200 Subject: [PATCH 09/17] Doing typeCheck for multi classes --- src/main/java/de/maishai/Compiler.java | 5 +- .../java/de/maishai/ExpressionGenerator.java | 2 +- .../typedast/Help/TypedExpressionHelp.java | 2 +- .../typedast/typedclass/TypedAssignment.java | 10 ++- .../typedast/typedclass/TypedClass.java | 8 +-- .../typedast/typedclass/TypedConstructor.java | 10 ++- .../typedast/typedclass/TypedDeclaration.java | 20 ++---- .../typedclass/TypedFieldVarAccess.java | 5 +- .../typedast/typedclass/TypedMethod.java | 10 ++- .../typedast/typedclass/TypedMethodCall.java | 68 ++++++++++++------- .../maishai/typedast/typedclass/TypedNew.java | 5 ++ .../typedast/typedclass/TypedProgram.java | 11 +-- 12 files changed, 100 insertions(+), 56 deletions(-) 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 3701aec..ce6a224 100644 --- a/src/main/java/de/maishai/ExpressionGenerator.java +++ b/src/main/java/de/maishai/ExpressionGenerator.java @@ -123,7 +123,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/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/typedclass/TypedAssignment.java b/src/main/java/de/maishai/typedast/typedclass/TypedAssignment.java index 556627e..16143fd 100644 --- a/src/main/java/de/maishai/typedast/typedclass/TypedAssignment.java +++ b/src/main/java/de/maishai/typedast/typedclass/TypedAssignment.java @@ -31,20 +31,24 @@ public class TypedAssignment implements TypedStatement { public Type typeCheck(TypedProgram typedProgram) { Type typeLeft = null; - if (typedProgram.getCurrentClass().isThereField(location.getName())) { + if (typedProgram.getCurrentClass().isThereField(location.getName()) && location.getField()) { 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 { + } else if(typedProgram.getCurrentClass().isThereField(location.getName())){ + typeLeft = typedProgram.getCurrentClass().getFieldType(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 { + }else if(typedProgram.getCurrentClass().isThereField(location.getName())){ + typeLeft = typedProgram.getCurrentClass().getFieldType(location.getName()); + }else { throw new RuntimeException("Variable " + location.getName() + " not declared in constructor"); } } diff --git a/src/main/java/de/maishai/typedast/typedclass/TypedClass.java b/src/main/java/de/maishai/typedast/typedclass/TypedClass.java index 94dc6f9..a994fcb 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()) { diff --git a/src/main/java/de/maishai/typedast/typedclass/TypedConstructor.java b/src/main/java/de/maishai/typedast/typedclass/TypedConstructor.java index 27c188a..f8ec43a 100644 --- a/src/main/java/de/maishai/typedast/typedclass/TypedConstructor.java +++ b/src/main/java/de/maishai/typedast/typedclass/TypedConstructor.java @@ -53,11 +53,19 @@ 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); diff --git a/src/main/java/de/maishai/typedast/typedclass/TypedDeclaration.java b/src/main/java/de/maishai/typedast/typedclass/TypedDeclaration.java index 4d9feb1..587df2d 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,20 @@ 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..3b29ade 100644 --- a/src/main/java/de/maishai/typedast/typedclass/TypedFieldVarAccess.java +++ b/src/main/java/de/maishai/typedast/typedclass/TypedFieldVarAccess.java @@ -34,7 +34,10 @@ public class TypedFieldVarAccess implements TypedExpression { if (field) { if (typedProgram.getCurrentClass().isThereField(name)) { type = typedProgram.getCurrentClass().getFieldType(name); - return typedProgram.getCurrentClass().getFieldType(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 "); } diff --git a/src/main/java/de/maishai/typedast/typedclass/TypedMethod.java b/src/main/java/de/maishai/typedast/typedclass/TypedMethod.java index 5b4eb3e..4bb93d9 100644 --- a/src/main/java/de/maishai/typedast/typedclass/TypedMethod.java +++ b/src/main/java/de/maishai/typedast/typedclass/TypedMethod.java @@ -28,7 +28,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( @@ -37,6 +40,11 @@ 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()); diff --git a/src/main/java/de/maishai/typedast/typedclass/TypedMethodCall.java b/src/main/java/de/maishai/typedast/typedclass/TypedMethodCall.java index e3fc6c9..21fe9d7 100644 --- a/src/main/java/de/maishai/typedast/typedclass/TypedMethodCall.java +++ b/src/main/java/de/maishai/typedast/typedclass/TypedMethodCall.java @@ -8,10 +8,10 @@ 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 @@ -26,38 +26,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..185e40f 100644 --- a/src/main/java/de/maishai/typedast/typedclass/TypedNew.java +++ b/src/main/java/de/maishai/typedast/typedclass/TypedNew.java @@ -28,6 +28,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; diff --git a/src/main/java/de/maishai/typedast/typedclass/TypedProgram.java b/src/main/java/de/maishai/typedast/typedclass/TypedProgram.java index 1e52857..e21c9ba 100644 --- a/src/main/java/de/maishai/typedast/typedclass/TypedProgram.java +++ b/src/main/java/de/maishai/typedast/typedclass/TypedProgram.java @@ -19,10 +19,14 @@ public class TypedProgram { public void startConversion(Program program) { + for(var clas : program.classes()){ + typedClasses.add(new TypedClass(clas)); + } + 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++; } @@ -39,9 +43,8 @@ public class TypedProgram { public TypedClass getTypedClass(String className) { 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) { From e51369715cfd8b2c3bacab3a390624fe79b300ee Mon Sep 17 00:00:00 2001 From: JonathanFleischmann Date: Wed, 15 May 2024 17:47:57 +0200 Subject: [PATCH 10/17] implemented test with complex class for parser and scanner --- .../AbstractSyntax_ComplexClass.java | 902 ++++++++++++++++++ .../resources/JavaTestfiles/ComplexClass.java | 78 +- ...edAbstractSyntax_ClassWithConstructor.java | 3 +- .../TypedAbstractSyntax_ClassWithField.java | 3 +- .../TypedAbstractSyntax_PublicClass.java | 3 +- src/test/java/CodegeneratorTests.java | 16 + src/test/java/ScannerParserTests.java | 2 +- 7 files changed, 968 insertions(+), 39 deletions(-) create mode 100644 src/main/resources/AbstractSyntax/AbstractSyntax_ComplexClass.java create mode 100644 src/test/java/CodegeneratorTests.java 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/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..8f2946f 100644 --- a/src/main/resources/TypedAbstractSyntax/TypedAbstractSyntax_ClassWithConstructor.java +++ b/src/main/resources/TypedAbstractSyntax/TypedAbstractSyntax_ClassWithConstructor.java @@ -37,7 +37,8 @@ public class TypedAbstractSyntax_ClassWithConstructor { null, Type.REFERENCE("ClassWithField") ) - ) + ), + null ); } 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_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..20dfd7a 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(AbstractSyntax_ComplexClass.get(), resultAst); } } From 7979aece642b9950d4f4ce62403cbb93966c265a Mon Sep 17 00:00:00 2001 From: ahmad Date: Wed, 15 May 2024 17:59:16 +0200 Subject: [PATCH 11/17] update typeCheck of TypedFieldVarAccess --- .../de/maishai/typedast/typedclass/TypedFieldVarAccess.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main/java/de/maishai/typedast/typedclass/TypedFieldVarAccess.java b/src/main/java/de/maishai/typedast/typedclass/TypedFieldVarAccess.java index 3b29ade..d7d5b36 100644 --- a/src/main/java/de/maishai/typedast/typedclass/TypedFieldVarAccess.java +++ b/src/main/java/de/maishai/typedast/typedclass/TypedFieldVarAccess.java @@ -52,6 +52,9 @@ public class TypedFieldVarAccess implements TypedExpression { } else if(typedProgram.getCurrentClass().isThereField(name)){ type = typedProgram.getCurrentClass().getFieldType(name); return type; + } else if(recursiveOwnerChain instanceof TypedFieldVarAccess typedFieldVarAccess){ + type = typedProgram.getCurrentClass().getFieldType(typedFieldVarAccess.getName()); + return type; } else { throw new RuntimeException("Variable " + name + " not declared in constructor"); @@ -67,6 +70,9 @@ public class TypedFieldVarAccess implements TypedExpression { } else if(typedProgram.getCurrentClass().isThereField(name)){ type = typedProgram.getCurrentClass().getFieldType(name); return type; + } else if(recursiveOwnerChain instanceof TypedFieldVarAccess typedFieldVarAccess){ + type = typedProgram.getCurrentClass().getFieldType(typedFieldVarAccess.getName()); + return type; } else { throw new RuntimeException("Variable " + name + " not declared in method"); From 1fb977f2486427e469b9469a2d86f6512b4f4ea7 Mon Sep 17 00:00:00 2001 From: ahmad Date: Wed, 15 May 2024 18:23:39 +0200 Subject: [PATCH 12/17] Refactored some typed classes --- .../typedast/typedclass/TypedAssignment.java | 64 +++++++---- .../typedast/typedclass/TypedDeclaration.java | 3 - .../typedclass/TypedFieldVarAccess.java | 103 ++++++++++-------- 3 files changed, 97 insertions(+), 73 deletions(-) diff --git a/src/main/java/de/maishai/typedast/typedclass/TypedAssignment.java b/src/main/java/de/maishai/typedast/typedclass/TypedAssignment.java index 16143fd..6a5e40d 100644 --- a/src/main/java/de/maishai/typedast/typedclass/TypedAssignment.java +++ b/src/main/java/de/maishai/typedast/typedclass/TypedAssignment.java @@ -29,31 +29,8 @@ public class TypedAssignment implements TypedStatement { @Override public Type typeCheck(TypedProgram typedProgram) { - Type typeLeft = null; - - if (typedProgram.getCurrentClass().isThereField(location.getName()) && location.getField()) { - 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 if(typedProgram.getCurrentClass().isThereField(location.getName())){ - typeLeft = typedProgram.getCurrentClass().getFieldType(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 if(typedProgram.getCurrentClass().isThereField(location.getName())){ - typeLeft = typedProgram.getCurrentClass().getFieldType(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)) { @@ -63,6 +40,45 @@ 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) { diff --git a/src/main/java/de/maishai/typedast/typedclass/TypedDeclaration.java b/src/main/java/de/maishai/typedast/typedclass/TypedDeclaration.java index 587df2d..34f5691 100644 --- a/src/main/java/de/maishai/typedast/typedclass/TypedDeclaration.java +++ b/src/main/java/de/maishai/typedast/typedclass/TypedDeclaration.java @@ -34,12 +34,9 @@ public final class TypedDeclaration implements TypedNode { throw new RuntimeException("Type " + type.getReference() + " not found"); } } - if (typedProgram.getCurrentClass().isThereField(name)) { throw new RuntimeException("Field " + name + " already declared"); } - - return type; } diff --git a/src/main/java/de/maishai/typedast/typedclass/TypedFieldVarAccess.java b/src/main/java/de/maishai/typedast/typedclass/TypedFieldVarAccess.java index d7d5b36..a575e85 100644 --- a/src/main/java/de/maishai/typedast/typedclass/TypedFieldVarAccess.java +++ b/src/main/java/de/maishai/typedast/typedclass/TypedFieldVarAccess.java @@ -32,55 +32,66 @@ public class TypedFieldVarAccess implements TypedExpression { @Override public Type typeCheck(TypedProgram typedProgram) { if (field) { - if (typedProgram.getCurrentClass().isThereField(name)) { - type = typedProgram.getCurrentClass().getFieldType(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 "); - } + type = checkFieldType(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 if(recursiveOwnerChain instanceof TypedFieldVarAccess typedFieldVarAccess){ - type = typedProgram.getCurrentClass().getFieldType(typedFieldVarAccess.getName()); - 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 if(recursiveOwnerChain instanceof TypedFieldVarAccess typedFieldVarAccess){ - type = typedProgram.getCurrentClass().getFieldType(typedFieldVarAccess.getName()); - 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 checkFieldType(TypedProgram typedProgram) { + if (typedProgram.getCurrentClass().isThereField(name)) { + type = typedProgram.getCurrentClass().getFieldType(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 checkFieldOrRecursiveType(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 checkFieldOrRecursiveType(typedProgram); + } + return type; + } + + private Type checkFieldOrRecursiveType(TypedProgram typedProgram) { + if (typedProgram.getCurrentClass().isThereField(name)) { + type = typedProgram.getCurrentClass().getFieldType(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) { From 0215d38aa1746bc4848c9b0f642aa3742b300610 Mon Sep 17 00:00:00 2001 From: ahmad Date: Wed, 15 May 2024 18:42:49 +0200 Subject: [PATCH 13/17] Updated the TypedFieldVarAccess --- .../typedast/typedclass/TypedClass.java | 17 +++++++++++++++++ .../typedclass/TypedFieldVarAccess.java | 18 ++++++++++++------ 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/src/main/java/de/maishai/typedast/typedclass/TypedClass.java b/src/main/java/de/maishai/typedast/typedclass/TypedClass.java index a994fcb..26085e1 100644 --- a/src/main/java/de/maishai/typedast/typedclass/TypedClass.java +++ b/src/main/java/de/maishai/typedast/typedclass/TypedClass.java @@ -117,6 +117,23 @@ 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/TypedFieldVarAccess.java b/src/main/java/de/maishai/typedast/typedclass/TypedFieldVarAccess.java index a575e85..337375b 100644 --- a/src/main/java/de/maishai/typedast/typedclass/TypedFieldVarAccess.java +++ b/src/main/java/de/maishai/typedast/typedclass/TypedFieldVarAccess.java @@ -32,17 +32,20 @@ public class TypedFieldVarAccess implements TypedExpression { @Override public Type typeCheck(TypedProgram typedProgram) { if (field) { - type = checkFieldType(typedProgram); + type = checkFieldOrMethodType(typedProgram); return type; } else { type = checkVariableType(typedProgram); return type; } } - private Type checkFieldType(TypedProgram typedProgram) { + 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; @@ -66,7 +69,7 @@ public class TypedFieldVarAccess implements TypedExpression { } else if (typedProgram.getCurrentClass().getCurrentConstructor().isLocalVariablePresent(name)) { type = typedProgram.getCurrentClass().getCurrentConstructor().getLocalVariableType(name); } else { - return checkFieldOrRecursiveType(typedProgram); + return checkFieldOrMethodOrRecursiveType(typedProgram); } return type; } @@ -77,15 +80,18 @@ public class TypedFieldVarAccess implements TypedExpression { } else if (typedProgram.getCurrentClass().getCurrentMethod().isLocalVariablePresent(name)) { type = typedProgram.getCurrentClass().getCurrentMethod().getLocalVariableType(name); } else { - return checkFieldOrRecursiveType(typedProgram); + return checkFieldOrMethodOrRecursiveType(typedProgram); } return type; } - private Type checkFieldOrRecursiveType(TypedProgram typedProgram) { + private Type checkFieldOrMethodOrRecursiveType(TypedProgram typedProgram) { if (typedProgram.getCurrentClass().isThereField(name)) { type = typedProgram.getCurrentClass().getFieldType(name); - } else if (recursiveOwnerChain instanceof TypedFieldVarAccess typedFieldVarAccess) { + }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"); From 5fe009806252dea5a1847020a3b42efb5e31e40f Mon Sep 17 00:00:00 2001 From: ahmad Date: Wed, 15 May 2024 18:50:43 +0200 Subject: [PATCH 14/17] Refactored typed classes --- .../java/de/maishai/typedast/typedclass/TypedBlock.java | 4 ++-- .../de/maishai/typedast/typedclass/TypedBoolLiteral.java | 4 ++-- .../java/de/maishai/typedast/typedclass/TypedBreak.java | 4 ---- .../java/de/maishai/typedast/typedclass/TypedClass.java | 1 + .../de/maishai/typedast/typedclass/TypedConstructor.java | 1 + .../de/maishai/typedast/typedclass/TypedDeclaration.java | 2 +- .../maishai/typedast/typedclass/TypedFieldVarAccess.java | 9 +++++---- .../java/de/maishai/typedast/typedclass/TypedMethod.java | 1 + .../java/de/maishai/typedast/typedclass/TypedNew.java | 4 ++-- .../de/maishai/typedast/typedclass/TypedProgram.java | 5 +++-- .../java/de/maishai/typedast/typedclass/TypedReturn.java | 4 ++-- .../java/de/maishai/typedast/typedclass/TypedUnary.java | 4 ++-- 12 files changed, 22 insertions(+), 21 deletions(-) diff --git a/src/main/java/de/maishai/typedast/typedclass/TypedBlock.java b/src/main/java/de/maishai/typedast/typedclass/TypedBlock.java index 0625aeb..e2a6709 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; diff --git a/src/main/java/de/maishai/typedast/typedclass/TypedBoolLiteral.java b/src/main/java/de/maishai/typedast/typedclass/TypedBoolLiteral.java index aa8b9e6..5c62c5b 100644 --- a/src/main/java/de/maishai/typedast/typedclass/TypedBoolLiteral.java +++ b/src/main/java/de/maishai/typedast/typedclass/TypedBoolLiteral.java @@ -32,9 +32,9 @@ 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); } } 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/TypedClass.java b/src/main/java/de/maishai/typedast/typedclass/TypedClass.java index 26085e1..bc61985 100644 --- a/src/main/java/de/maishai/typedast/typedclass/TypedClass.java +++ b/src/main/java/de/maishai/typedast/typedclass/TypedClass.java @@ -125,6 +125,7 @@ public class TypedClass implements TypedNode { } return false; } + public Type getMethodType(String methodName) { for (TypedMethod m : typedMethods) { if (m.getName().equals(methodName)) { diff --git a/src/main/java/de/maishai/typedast/typedclass/TypedConstructor.java b/src/main/java/de/maishai/typedast/typedclass/TypedConstructor.java index f8ec43a..3f18cde 100644 --- a/src/main/java/de/maishai/typedast/typedclass/TypedConstructor.java +++ b/src/main/java/de/maishai/typedast/typedclass/TypedConstructor.java @@ -66,6 +66,7 @@ public class TypedConstructor implements TypedNode { throw new RuntimeException("Parameter " + paraName + " already exists"); } } + public void convertToBlock(TypedProgram typedProgram, Constructor unTypedConstructor) { this.typedBlock = new TypedBlock(typedProgram, unTypedConstructor.block()); typeCheck(typedProgram); diff --git a/src/main/java/de/maishai/typedast/typedclass/TypedDeclaration.java b/src/main/java/de/maishai/typedast/typedclass/TypedDeclaration.java index 34f5691..d653b54 100644 --- a/src/main/java/de/maishai/typedast/typedclass/TypedDeclaration.java +++ b/src/main/java/de/maishai/typedast/typedclass/TypedDeclaration.java @@ -29,7 +29,7 @@ public final class TypedDeclaration implements TypedNode { @Override public Type typeCheck(TypedProgram typedProgram) { - if(type.getReference() != null && !typedProgram.getCurrentClass().getClassName().equals(type.getReference())) { + if (type.getReference() != null && !typedProgram.getCurrentClass().getClassName().equals(type.getReference())) { if (!typedProgram.isTypedClassPresent(type.getReference())) { throw new RuntimeException("Type " + type.getReference() + " not found"); } diff --git a/src/main/java/de/maishai/typedast/typedclass/TypedFieldVarAccess.java b/src/main/java/de/maishai/typedast/typedclass/TypedFieldVarAccess.java index 337375b..1a404d1 100644 --- a/src/main/java/de/maishai/typedast/typedclass/TypedFieldVarAccess.java +++ b/src/main/java/de/maishai/typedast/typedclass/TypedFieldVarAccess.java @@ -39,11 +39,12 @@ public class TypedFieldVarAccess implements TypedExpression { 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)) { + } else if (typedProgram.getCurrentClass().isMethodOfCurrentClass(name)) { type = typedProgram.getCurrentClass().getMethodType(name); return type; } else if (recursiveOwnerChain instanceof TypedFieldVarAccess typedFieldVarAccess) { @@ -53,6 +54,7 @@ public class TypedFieldVarAccess implements TypedExpression { throw new RuntimeException("Field " + name + " not declared"); } } + private Type checkVariableType(TypedProgram typedProgram) { if (typedProgram.getCurrentClass().isCurrentConstructorPresent()) { return checkConstructorVariableType(typedProgram); @@ -88,10 +90,9 @@ public class TypedFieldVarAccess implements TypedExpression { private Type checkFieldOrMethodOrRecursiveType(TypedProgram typedProgram) { if (typedProgram.getCurrentClass().isThereField(name)) { type = typedProgram.getCurrentClass().getFieldType(name); - }else if(typedProgram.getCurrentClass().isMethodOfCurrentClass(name)) { + } else if (typedProgram.getCurrentClass().isMethodOfCurrentClass(name)) { type = typedProgram.getCurrentClass().getMethodType(name); - } - else if (recursiveOwnerChain instanceof TypedFieldVarAccess typedFieldVarAccess) { + } else if (recursiveOwnerChain instanceof TypedFieldVarAccess typedFieldVarAccess) { type = typedProgram.getCurrentClass().getFieldType(typedFieldVarAccess.getName()); } else { throw new RuntimeException("Variable " + name + " not declared"); diff --git a/src/main/java/de/maishai/typedast/typedclass/TypedMethod.java b/src/main/java/de/maishai/typedast/typedclass/TypedMethod.java index 4bb93d9..faedd43 100644 --- a/src/main/java/de/maishai/typedast/typedclass/TypedMethod.java +++ b/src/main/java/de/maishai/typedast/typedclass/TypedMethod.java @@ -40,6 +40,7 @@ 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"); diff --git a/src/main/java/de/maishai/typedast/typedclass/TypedNew.java b/src/main/java/de/maishai/typedast/typedclass/TypedNew.java index 185e40f..35d446f 100644 --- a/src/main/java/de/maishai/typedast/typedclass/TypedNew.java +++ b/src/main/java/de/maishai/typedast/typedclass/TypedNew.java @@ -29,8 +29,8 @@ public class TypedNew implements TypedExpression, TypedStatement { @Override public Type typeCheck(TypedProgram typedProgram) { - if(typedProgram.isTypedClassPresent(type.getReference())){ - return Type.REFERENCE(type.getReference()); + if (typedProgram.isTypedClassPresent(type.getReference())) { + return Type.REFERENCE(type.getReference()); } for (var constructor : typedProgram.getCurrentClass().getTypedConstructors()) { diff --git a/src/main/java/de/maishai/typedast/typedclass/TypedProgram.java b/src/main/java/de/maishai/typedast/typedclass/TypedProgram.java index e21c9ba..f57460b 100644 --- a/src/main/java/de/maishai/typedast/typedclass/TypedProgram.java +++ b/src/main/java/de/maishai/typedast/typedclass/TypedProgram.java @@ -19,7 +19,7 @@ public class TypedProgram { public void startConversion(Program program) { - for(var clas : program.classes()){ + for (var clas : program.classes()) { typedClasses.add(new TypedClass(clas)); } @@ -32,7 +32,7 @@ public class TypedProgram { } int i = 0; - for(var clas : program.classes()){ + for (var clas : program.classes()) { enterCurrentClass(typedClasses.get(i)); typedClasses.get(i).covertBlocksOfConstructorsAndMethods(this, clas); exitCurrentClass(); @@ -43,6 +43,7 @@ public class TypedProgram { public TypedClass getTypedClass(String className) { return typedClasses.stream().filter(clas -> clas.getClassName().equals(className)).findFirst().get(); } + public boolean isTypedClassPresent(String className) { return typedClasses.stream().anyMatch(clas -> clas.getClassName().equals(className)); } diff --git a/src/main/java/de/maishai/typedast/typedclass/TypedReturn.java b/src/main/java/de/maishai/typedast/typedclass/TypedReturn.java index 9995c2e..4562552 100644 --- a/src/main/java/de/maishai/typedast/typedclass/TypedReturn.java +++ b/src/main/java/de/maishai/typedast/typedclass/TypedReturn.java @@ -21,9 +21,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(); } } 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); } } From 3e63f309d93d99fa603054f30016c7d2d3c01fcd Mon Sep 17 00:00:00 2001 From: ahmad Date: Wed, 15 May 2024 19:12:49 +0200 Subject: [PATCH 15/17] Add some docu for TypedProgram --- src/main/java/de/maishai/typedast/typedclass/TypedProgram.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/de/maishai/typedast/typedclass/TypedProgram.java b/src/main/java/de/maishai/typedast/typedclass/TypedProgram.java index f57460b..f8dbd2e 100644 --- a/src/main/java/de/maishai/typedast/typedclass/TypedProgram.java +++ b/src/main/java/de/maishai/typedast/typedclass/TypedProgram.java @@ -19,10 +19,12 @@ 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)); @@ -31,6 +33,7 @@ public class TypedProgram { k++; } + // Konvertiere die Blöcke der Konstruktoren und Methoden von den jeweiligen Klassen int i = 0; for (var clas : program.classes()) { enterCurrentClass(typedClasses.get(i)); From 4aa2a52480f0d0341c76bf86495b600291cab160 Mon Sep 17 00:00:00 2001 From: ahmad Date: Wed, 15 May 2024 22:42:58 +0200 Subject: [PATCH 16/17] Retrieve typeCheck in TypedAssignment --- .../java/de/maishai/typedast/typedclass/TypedAssignment.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/de/maishai/typedast/typedclass/TypedAssignment.java b/src/main/java/de/maishai/typedast/typedclass/TypedAssignment.java index 7985d3f..91b92ea 100644 --- a/src/main/java/de/maishai/typedast/typedclass/TypedAssignment.java +++ b/src/main/java/de/maishai/typedast/typedclass/TypedAssignment.java @@ -25,6 +25,7 @@ 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 From 2eecf3faa8990a26e2f42d04122bab3f7fe5f682 Mon Sep 17 00:00:00 2001 From: JonathanFleischmann Date: Thu, 16 May 2024 00:09:05 +0200 Subject: [PATCH 17/17] implemented test with complex class for type check --- .../typedast/typedclass/TypedAssignment.java | 1 + .../typedast/typedclass/TypedBoolLiteral.java | 2 + .../typedast/typedclass/TypedCharLiteral.java | 2 + .../typedast/typedclass/TypedIfElse.java | 2 + .../typedast/typedclass/TypedMethod.java | 2 + .../typedast/typedclass/TypedMethodCall.java | 2 + .../maishai/typedast/typedclass/TypedNew.java | 2 + .../typedast/typedclass/TypedProgram.java | 14 + .../typedast/typedclass/TypedReturn.java | 2 + .../AbstractSyntax_ClassWithConstructor.java | 1 - ...edAbstractSyntax_ClassWithConstructor.java | 12 +- .../TypedAbstractSyntax_ComplexClass.java | 960 ++++++++++++++++++ src/test/java/ScannerParserTests.java | 2 +- src/test/java/TypingTests.java | 6 + 14 files changed, 1002 insertions(+), 8 deletions(-) create mode 100644 src/main/resources/TypedAbstractSyntax/TypedAbstractSyntax_ComplexClass.java diff --git a/src/main/java/de/maishai/typedast/typedclass/TypedAssignment.java b/src/main/java/de/maishai/typedast/typedclass/TypedAssignment.java index 7985d3f..91b92ea 100644 --- a/src/main/java/de/maishai/typedast/typedclass/TypedAssignment.java +++ b/src/main/java/de/maishai/typedast/typedclass/TypedAssignment.java @@ -25,6 +25,7 @@ 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 diff --git a/src/main/java/de/maishai/typedast/typedclass/TypedBoolLiteral.java b/src/main/java/de/maishai/typedast/typedclass/TypedBoolLiteral.java index 22f7b3f..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; diff --git a/src/main/java/de/maishai/typedast/typedclass/TypedCharLiteral.java b/src/main/java/de/maishai/typedast/typedclass/TypedCharLiteral.java index 371abfe..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; 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/TypedMethod.java b/src/main/java/de/maishai/typedast/typedclass/TypedMethod.java index f71d5c8..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; diff --git a/src/main/java/de/maishai/typedast/typedclass/TypedMethodCall.java b/src/main/java/de/maishai/typedast/typedclass/TypedMethodCall.java index 21fe9d7..83353a4 100644 --- a/src/main/java/de/maishai/typedast/typedclass/TypedMethodCall.java +++ b/src/main/java/de/maishai/typedast/typedclass/TypedMethodCall.java @@ -3,6 +3,7 @@ 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; @@ -15,6 +16,7 @@ import static de.maishai.typedast.Help.TypedExpressionHelp.convertExpression; @Data @NoArgsConstructor +@AllArgsConstructor public class TypedMethodCall implements TypedExpression, TypedStatement { private TypedFieldVarAccess recipient; private List args = new ArrayList<>(); diff --git a/src/main/java/de/maishai/typedast/typedclass/TypedNew.java b/src/main/java/de/maishai/typedast/typedclass/TypedNew.java index 9c8497e..c5cc3b5 100644 --- a/src/main/java/de/maishai/typedast/typedclass/TypedNew.java +++ b/src/main/java/de/maishai/typedast/typedclass/TypedNew.java @@ -3,6 +3,7 @@ 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; @@ -13,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<>(); diff --git a/src/main/java/de/maishai/typedast/typedclass/TypedProgram.java b/src/main/java/de/maishai/typedast/typedclass/TypedProgram.java index f8dbd2e..d30440b 100644 --- a/src/main/java/de/maishai/typedast/typedclass/TypedProgram.java +++ b/src/main/java/de/maishai/typedast/typedclass/TypedProgram.java @@ -59,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 06a854e..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; 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/TypedAbstractSyntax/TypedAbstractSyntax_ClassWithConstructor.java b/src/main/resources/TypedAbstractSyntax/TypedAbstractSyntax_ClassWithConstructor.java index 8f2946f..49c4cd8 100644 --- a/src/main/resources/TypedAbstractSyntax/TypedAbstractSyntax_ClassWithConstructor.java +++ b/src/main/resources/TypedAbstractSyntax/TypedAbstractSyntax_ClassWithConstructor.java @@ -35,7 +35,7 @@ public class TypedAbstractSyntax_ClassWithConstructor { getConstructors(), null, null, - Type.REFERENCE("ClassWithField") + Type.REFERENCE("ClassWithConstructor") ) ), null @@ -204,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_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/test/java/ScannerParserTests.java b/src/test/java/ScannerParserTests.java index 20dfd7a..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_ComplexClass.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); + } }