From 30a62a662193af7dca43bfd540a7bb59d918a275 Mon Sep 17 00:00:00 2001 From: luca9913 Date: Thu, 1 Jun 2023 20:59:16 +0200 Subject: [PATCH] bug fix VectorNotObject test --- pom.xml | 7 +- .../de/dhbwstuttgart/bytecode/Codegen.java | 1252 ++++++++--------- .../StatementGenerator.java | 16 +- .../generate/StatementToTargetExpression.java | 2 +- src/test/java/targetast/TestComplete.java | 69 +- 5 files changed, 647 insertions(+), 699 deletions(-) diff --git a/pom.xml b/pom.xml index adef032f..ea943bac 100644 --- a/pom.xml +++ b/pom.xml @@ -51,11 +51,10 @@ http://maven.apache.org/maven-v4_0_0.xsd"> org.apache.maven.plugins maven-compiler-plugin - 3.8.0 + 3.11.0 --enable-preview - 19 - 19 + 20 @@ -112,8 +111,6 @@ http://maven.apache.org/maven-v4_0_0.xsd"> - 19 - 19 de.dhbwstuttgart.core.ConsoleInterface diff --git a/src/main/java/de/dhbwstuttgart/bytecode/Codegen.java b/src/main/java/de/dhbwstuttgart/bytecode/Codegen.java index df56b333..4b5645b9 100644 --- a/src/main/java/de/dhbwstuttgart/bytecode/Codegen.java +++ b/src/main/java/de/dhbwstuttgart/bytecode/Codegen.java @@ -28,7 +28,8 @@ public class Codegen { this.cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS); } - private record LocalVar(int index, String name, TargetType type) {} + private record LocalVar(int index, String name, TargetType type) { + } private static class Scope { Scope parent; @@ -196,9 +197,7 @@ public class Codegen { mv.visitInsn(L2F); else if (dest.equals(TargetType.Double)) mv.visitInsn(L2D); - else if (dest.equals(TargetType.Byte) - || dest.equals(TargetType.Char) - || dest.equals(TargetType.Short)) { + else if (dest.equals(TargetType.Byte) || dest.equals(TargetType.Char) || dest.equals(TargetType.Short)) { mv.visitInsn(L2I); convertTo(state, TargetType.Integer, dest); } @@ -209,9 +208,7 @@ public class Codegen { mv.visitInsn(F2D); else if (dest.equals(TargetType.Long)) mv.visitInsn(F2L); - else if (dest.equals(TargetType.Byte) - || dest.equals(TargetType.Char) - || dest.equals(TargetType.Short)) { + else if (dest.equals(TargetType.Byte) || dest.equals(TargetType.Char) || dest.equals(TargetType.Short)) { mv.visitInsn(F2I); convertTo(state, TargetType.Integer, dest); } @@ -222,16 +219,11 @@ public class Codegen { mv.visitInsn(D2F); else if (dest.equals(TargetType.Long)) mv.visitInsn(D2L); - else if (dest.equals(TargetType.Byte) - || dest.equals(TargetType.Char) - || dest.equals(TargetType.Short)) { + else if (dest.equals(TargetType.Byte) || dest.equals(TargetType.Char) || dest.equals(TargetType.Short)) { mv.visitInsn(D2I); convertTo(state, TargetType.Integer, dest); } - } else if (source.equals(TargetType.Byte) - || source.equals(TargetType.Char) - || source.equals(TargetType.Short) - || source.equals(TargetType.Integer)) { + } else if (source.equals(TargetType.Byte) || source.equals(TargetType.Char) || source.equals(TargetType.Short) || source.equals(TargetType.Integer)) { if (dest.equals(TargetType.Byte)) mv.visitInsn(I2B); else if (dest.equals(TargetType.Char)) @@ -268,309 +260,293 @@ public class Codegen { private void generateBinaryOp(State state, TargetBinaryOp op) { var mv = state.mv; switch (op) { - case Add add: { - if (add.type().equals(TargetType.String)) { - mv.visitTypeInsn(NEW, "java/lang/StringBuilder"); - mv.visitInsn(DUP); - generate(state, add.left()); - convertToString(state, add.left().type()); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/StringBuilder", "", "(Ljava/lang/String;)V", false); - } else { - generate(state, add.left()); - convertTo(state, add.left().type(), add.type()); - generate(state, add.right()); - convertTo(state, add.right().type(), add.type()); - var type = add.type(); - if (type.equals(TargetType.Byte) - || type.equals(TargetType.Char) - || type.equals(TargetType.Integer) - || type.equals(TargetType.Short)) { - mv.visitInsn(IADD); - } else if (type.equals(TargetType.Long)) { - mv.visitInsn(LADD); - } else if (type.equals(TargetType.Float)) { - mv.visitInsn(FADD); - } else if (type.equals(TargetType.Double)) { - mv.visitInsn(DADD); - } else { - throw new CodeGenException("Invalid argument to Add expression"); - } - } - if (add.type().equals(TargetType.String)) { - generate(state, add.right()); - convertToString(state, add.right().type()); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(Ljava/lang/String;)Ljava/lang/StringBuilder;", false); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "toString", "()Ljava/lang/String;", false); - } - break; - } - case Sub sub: { - generate(state, sub.left()); - convertTo(state, sub.left().type(), op.type()); - generate(state, sub.right()); - convertTo(state, sub.right().type(), op.type()); - var type = sub.type(); - if (type.equals(TargetType.Byte) - || type.equals(TargetType.Char) - || type.equals(TargetType.Integer) - || type.equals(TargetType.Short)) { - mv.visitInsn(ISUB); + case Add add: { + if (add.type().equals(TargetType.String)) { + mv.visitTypeInsn(NEW, "java/lang/StringBuilder"); + mv.visitInsn(DUP); + generate(state, add.left()); + convertToString(state, add.left().type()); + mv.visitMethodInsn(INVOKESPECIAL, "java/lang/StringBuilder", "", "(Ljava/lang/String;)V", false); + } else { + generate(state, add.left()); + convertTo(state, add.left().type(), add.type()); + generate(state, add.right()); + convertTo(state, add.right().type(), add.type()); + var type = add.type(); + if (type.equals(TargetType.Byte) || type.equals(TargetType.Char) || type.equals(TargetType.Integer) || type.equals(TargetType.Short)) { + mv.visitInsn(IADD); } else if (type.equals(TargetType.Long)) { - mv.visitInsn(LSUB); + mv.visitInsn(LADD); } else if (type.equals(TargetType.Float)) { - mv.visitInsn(FSUB); + mv.visitInsn(FADD); } else if (type.equals(TargetType.Double)) { - mv.visitInsn(DSUB); + mv.visitInsn(DADD); } else { - throw new CodeGenException("Invalid argument to Sub expression"); + throw new CodeGenException("Invalid argument to Add expression"); } - break; } - case Div div: { - generate(state, div.left()); - convertTo(state, div.left().type(), op.type()); - generate(state, div.right()); - convertTo(state, div.right().type(), op.type()); - var type = div.type(); - if (type.equals(TargetType.Byte) - || type.equals(TargetType.Char) - || type.equals(TargetType.Integer) - || type.equals(TargetType.Short)) { - mv.visitInsn(IDIV); - } else if (type.equals(TargetType.Long)) { - mv.visitInsn(LDIV); - } else if (type.equals(TargetType.Float)) { - mv.visitInsn(FDIV); - } else if (type.equals(TargetType.Double)) { - mv.visitInsn(DDIV); - } else { - throw new CodeGenException("Invalid argument to Div expression"); - } - break; + if (add.type().equals(TargetType.String)) { + generate(state, add.right()); + convertToString(state, add.right().type()); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(Ljava/lang/String;)Ljava/lang/StringBuilder;", false); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "toString", "()Ljava/lang/String;", false); } - case Mul mul: { - generate(state, mul.left()); - convertTo(state, mul.left().type(), op.type()); - generate(state, mul.right()); - convertTo(state, mul.right().type(), op.type()); - var type = mul.type(); - if (type.equals(TargetType.Byte) - || type.equals(TargetType.Char) - || type.equals(TargetType.Integer) - || type.equals(TargetType.Short)) { - mv.visitInsn(IMUL); - } else if (type.equals(TargetType.Long)) { - mv.visitInsn(LMUL); - } else if (type.equals(TargetType.Float)) { - mv.visitInsn(FMUL); - } else if (type.equals(TargetType.Double)) { - mv.visitInsn(DMUL); - } else { - throw new CodeGenException("Invalid argument to Mul expression"); - } - break; + break; + } + case Sub sub: { + generate(state, sub.left()); + convertTo(state, sub.left().type(), op.type()); + generate(state, sub.right()); + convertTo(state, sub.right().type(), op.type()); + var type = sub.type(); + if (type.equals(TargetType.Byte) || type.equals(TargetType.Char) || type.equals(TargetType.Integer) || type.equals(TargetType.Short)) { + mv.visitInsn(ISUB); + } else if (type.equals(TargetType.Long)) { + mv.visitInsn(LSUB); + } else if (type.equals(TargetType.Float)) { + mv.visitInsn(FSUB); + } else if (type.equals(TargetType.Double)) { + mv.visitInsn(DSUB); + } else { + throw new CodeGenException("Invalid argument to Sub expression"); } - case Rem rem: { - generate(state, rem.left()); - convertTo(state, rem.left().type(), op.type()); - generate(state, rem.right()); - convertTo(state, rem.right().type(), op.type()); - var type = rem.type(); - if (type.equals(TargetType.Byte) - || type.equals(TargetType.Char) - || type.equals(TargetType.Integer) - || type.equals(TargetType.Short)) { - mv.visitInsn(IREM); - } else if (type.equals(TargetType.Long)) { - mv.visitInsn(LREM); - } else if (type.equals(TargetType.Float)) { - mv.visitInsn(FREM); - } else if (type.equals(TargetType.Double)) { - mv.visitInsn(DREM); - } else { - throw new CodeGenException("Invalid argument to Rem expression"); - } - break; + break; + } + case Div div: { + generate(state, div.left()); + convertTo(state, div.left().type(), op.type()); + generate(state, div.right()); + convertTo(state, div.right().type(), op.type()); + var type = div.type(); + if (type.equals(TargetType.Byte) || type.equals(TargetType.Char) || type.equals(TargetType.Integer) || type.equals(TargetType.Short)) { + mv.visitInsn(IDIV); + } else if (type.equals(TargetType.Long)) { + mv.visitInsn(LDIV); + } else if (type.equals(TargetType.Float)) { + mv.visitInsn(FDIV); + } else if (type.equals(TargetType.Double)) { + mv.visitInsn(DDIV); + } else { + throw new CodeGenException("Invalid argument to Div expression"); } - case Or or: { - Label or_false = new Label(); - Label or_true = new Label(); - Label end = new Label(); - generate(state, or.left()); - mv.visitJumpInsn(IFNE, or_true); - generate(state, or.right()); - mv.visitJumpInsn(IFEQ, or_false); - mv.visitLabel(or_true); - mv.visitInsn(ICONST_1); - mv.visitJumpInsn(GOTO, end); - mv.visitLabel(or_false); - mv.visitInsn(ICONST_0); - mv.visitLabel(end); - break; + break; + } + case Mul mul: { + generate(state, mul.left()); + convertTo(state, mul.left().type(), op.type()); + generate(state, mul.right()); + convertTo(state, mul.right().type(), op.type()); + var type = mul.type(); + if (type.equals(TargetType.Byte) || type.equals(TargetType.Char) || type.equals(TargetType.Integer) || type.equals(TargetType.Short)) { + mv.visitInsn(IMUL); + } else if (type.equals(TargetType.Long)) { + mv.visitInsn(LMUL); + } else if (type.equals(TargetType.Float)) { + mv.visitInsn(FMUL); + } else if (type.equals(TargetType.Double)) { + mv.visitInsn(DMUL); + } else { + throw new CodeGenException("Invalid argument to Mul expression"); } - case And and: { - Label and_false = new Label(); - Label end = new Label(); - generate(state, and.left()); - mv.visitJumpInsn(IFEQ, and_false); - generate(state, and.right()); - mv.visitJumpInsn(IFEQ, and_false); - mv.visitInsn(ICONST_1); - mv.visitJumpInsn(GOTO, end); - mv.visitLabel(and_false); - mv.visitInsn(ICONST_0); - mv.visitLabel(end); - break; + break; + } + case Rem rem: { + generate(state, rem.left()); + convertTo(state, rem.left().type(), op.type()); + generate(state, rem.right()); + convertTo(state, rem.right().type(), op.type()); + var type = rem.type(); + if (type.equals(TargetType.Byte) || type.equals(TargetType.Char) || type.equals(TargetType.Integer) || type.equals(TargetType.Short)) { + mv.visitInsn(IREM); + } else if (type.equals(TargetType.Long)) { + mv.visitInsn(LREM); + } else if (type.equals(TargetType.Float)) { + mv.visitInsn(FREM); + } else if (type.equals(TargetType.Double)) { + mv.visitInsn(DREM); + } else { + throw new CodeGenException("Invalid argument to Rem expression"); } - case BAnd band: { - generate(state, band.left()); - convertTo(state, band.left().type(), op.type()); - generate(state, band.right()); - convertTo(state, band.right().type(), op.type()); - if (band.type().equals(TargetType.Long)) - mv.visitInsn(LAND); - else mv.visitInsn(IAND); - break; + break; + } + case Or or: { + Label or_false = new Label(); + Label or_true = new Label(); + Label end = new Label(); + generate(state, or.left()); + mv.visitJumpInsn(IFNE, or_true); + generate(state, or.right()); + mv.visitJumpInsn(IFEQ, or_false); + mv.visitLabel(or_true); + mv.visitInsn(ICONST_1); + mv.visitJumpInsn(GOTO, end); + mv.visitLabel(or_false); + mv.visitInsn(ICONST_0); + mv.visitLabel(end); + break; + } + case And and: { + Label and_false = new Label(); + Label end = new Label(); + generate(state, and.left()); + mv.visitJumpInsn(IFEQ, and_false); + generate(state, and.right()); + mv.visitJumpInsn(IFEQ, and_false); + mv.visitInsn(ICONST_1); + mv.visitJumpInsn(GOTO, end); + mv.visitLabel(and_false); + mv.visitInsn(ICONST_0); + mv.visitLabel(end); + break; + } + case BAnd band: { + generate(state, band.left()); + convertTo(state, band.left().type(), op.type()); + generate(state, band.right()); + convertTo(state, band.right().type(), op.type()); + if (band.type().equals(TargetType.Long)) + mv.visitInsn(LAND); + else + mv.visitInsn(IAND); + break; + } + case BOr bor: { + generate(state, bor.left()); + convertTo(state, bor.left().type(), op.type()); + generate(state, bor.right()); + convertTo(state, bor.right().type(), op.type()); + if (bor.type().equals(TargetType.Long)) + mv.visitInsn(LOR); + else + mv.visitInsn(IOR); + break; + } + case XOr xor: { + generate(state, xor.left()); + convertTo(state, xor.left().type(), op.type()); + generate(state, xor.right()); + convertTo(state, xor.right().type(), op.type()); + if (xor.type().equals(TargetType.Long)) + mv.visitInsn(LXOR); + else + mv.visitInsn(IXOR); + break; + } + case Shl shl: { + generate(state, shl.left()); + convertTo(state, shl.left().type(), op.type()); + generate(state, shl.right()); + convertTo(state, shl.right().type(), op.type()); + if (shl.type().equals(TargetType.Long)) + mv.visitInsn(LSHL); + else + mv.visitInsn(ISHL); + break; + } + case Shr shr: { + generate(state, shr.left()); + convertTo(state, shr.left().type(), op.type()); + generate(state, shr.right()); + convertTo(state, shr.right().type(), op.type()); + if (shr.type().equals(TargetType.Long)) + mv.visitInsn(LSHR); + else + mv.visitInsn(ISHR); + break; + } + case UShr ushr: { + generate(state, ushr.left()); + convertTo(state, ushr.left().type(), op.type()); + generate(state, ushr.right()); + convertTo(state, ushr.right().type(), op.type()); + if (ushr.type().equals(TargetType.Long)) + mv.visitInsn(LUSHR); + else + mv.visitInsn(IUSHR); + break; + } + case Greater greater: { + var type = largerType(greater.left().type(), greater.right().type()); + if (type.equals(TargetType.Long)) { + generateRelationalOperator(state, greater, type, LCMP, IFGT); + } else if (type.equals(TargetType.Float)) { + generateRelationalOperator(state, greater, type, FCMPL, IFGT); + } else if (type.equals(TargetType.Double)) { + generateRelationalOperator(state, greater, type, DCMPL, IFGT); + } else { + generateRelationalOperator(state, greater, type, IF_ICMPGT); } - case BOr bor: { - generate(state, bor.left()); - convertTo(state, bor.left().type(), op.type()); - generate(state, bor.right()); - convertTo(state, bor.right().type(), op.type()); - if (bor.type().equals(TargetType.Long)) - mv.visitInsn(LOR); - else mv.visitInsn(IOR); - break; + break; + } + case Less less: { + var type = largerType(less.left().type(), less.right().type()); + if (type.equals(TargetType.Long)) { + generateRelationalOperator(state, less, type, LCMP, IFLT); + } else if (type.equals(TargetType.Float)) { + generateRelationalOperator(state, less, type, FCMPL, IFLT); + } else if (type.equals(TargetType.Double)) { + generateRelationalOperator(state, less, type, DCMPL, IFLT); + } else { + generateRelationalOperator(state, less, type, IF_ICMPLT); } - case XOr xor: { - generate(state, xor.left()); - convertTo(state, xor.left().type(), op.type()); - generate(state, xor.right()); - convertTo(state, xor.right().type(), op.type()); - if (xor.type().equals(TargetType.Long)) - mv.visitInsn(LXOR); - else mv.visitInsn(IXOR); - break; + break; + } + case GreaterOrEqual greaterOrEqual: { + var type = largerType(greaterOrEqual.left().type(), greaterOrEqual.right().type()); + if (type.equals(TargetType.Long)) { + generateRelationalOperator(state, greaterOrEqual, type, LCMP, IFGE); + } else if (type.equals(TargetType.Float)) { + generateRelationalOperator(state, greaterOrEqual, type, FCMPL, IFGE); + } else if (type.equals(TargetType.Double)) { + generateRelationalOperator(state, greaterOrEqual, type, DCMPL, IFGE); + } else { + generateRelationalOperator(state, greaterOrEqual, type, IF_ICMPGE); } - case Shl shl: { - generate(state, shl.left()); - convertTo(state, shl.left().type(), op.type()); - generate(state, shl.right()); - convertTo(state, shl.right().type(), op.type()); - if (shl.type().equals(TargetType.Long)) - mv.visitInsn(LSHL); - else mv.visitInsn(ISHL); - break; + break; + } + case LessOrEqual lessOrEqual: { + var type = largerType(lessOrEqual.left().type(), lessOrEqual.right().type()); + if (type.equals(TargetType.Long)) { + generateRelationalOperator(state, lessOrEqual, type, LCMP, IFLE); + } else if (type.equals(TargetType.Float)) { + generateRelationalOperator(state, lessOrEqual, type, FCMPL, IFLE); + } else if (type.equals(TargetType.Double)) { + generateRelationalOperator(state, lessOrEqual, type, DCMPL, IFLE); + } else { + generateRelationalOperator(state, lessOrEqual, type, IF_ICMPLE); } - case Shr shr: { - generate(state, shr.left()); - convertTo(state, shr.left().type(), op.type()); - generate(state, shr.right()); - convertTo(state, shr.right().type(), op.type()); - if (shr.type().equals(TargetType.Long)) - mv.visitInsn(LSHR); - else mv.visitInsn(ISHR); - break; + break; + } + case Equal equal: { + var type = largerType(equal.left().type(), equal.right().type()); + if (type.equals(TargetType.Long)) { + generateRelationalOperator(state, equal, type, LCMP, IFEQ); + } else if (type.equals(TargetType.Float)) { + generateRelationalOperator(state, equal, type, FCMPL, IFEQ); + } else if (type.equals(TargetType.Double)) { + generateRelationalOperator(state, equal, type, DCMPL, IFEQ); + } else if (type.equals(TargetType.Char) || type.equals(TargetType.Short) || type.equals(TargetType.Byte) || type.equals(TargetType.Integer) || type.equals(TargetType.Boolean)) { + generateRelationalOperator(state, equal, type, IF_ICMPEQ); + } else { + generateRelationalOperator(state, equal, type, IF_ACMPEQ); } - case UShr ushr: { - generate(state, ushr.left()); - convertTo(state, ushr.left().type(), op.type()); - generate(state, ushr.right()); - convertTo(state, ushr.right().type(), op.type()); - if (ushr.type().equals(TargetType.Long)) - mv.visitInsn(LUSHR); - else mv.visitInsn(IUSHR); - break; - } - case Greater greater: { - var type = largerType(greater.left().type(), greater.right().type()); - if (type.equals(TargetType.Long)) { - generateRelationalOperator(state, greater, type, LCMP, IFGT); - } else if (type.equals(TargetType.Float)) { - generateRelationalOperator(state, greater, type, FCMPL, IFGT); - } else if (type.equals(TargetType.Double)) { - generateRelationalOperator(state, greater, type, DCMPL, IFGT); - } else { - generateRelationalOperator(state, greater, type, IF_ICMPGT); - } - break; - } - case Less less: { - var type = largerType(less.left().type(), less.right().type()); - if (type.equals(TargetType.Long)) { - generateRelationalOperator(state, less, type, LCMP, IFLT); - } else if (type.equals(TargetType.Float)) { - generateRelationalOperator(state, less, type, FCMPL, IFLT); - } else if (type.equals(TargetType.Double)) { - generateRelationalOperator(state, less, type, DCMPL, IFLT); - } else { - generateRelationalOperator(state, less, type, IF_ICMPLT); - } - break; - } - case GreaterOrEqual greaterOrEqual: { - var type = largerType(greaterOrEqual.left().type(), greaterOrEqual.right().type()); - if (type.equals(TargetType.Long)) { - generateRelationalOperator(state, greaterOrEqual, type, LCMP, IFGE); - } else if (type.equals(TargetType.Float)) { - generateRelationalOperator(state, greaterOrEqual, type, FCMPL, IFGE); - } else if (type.equals(TargetType.Double)) { - generateRelationalOperator(state, greaterOrEqual, type, DCMPL, IFGE); - } else { - generateRelationalOperator(state, greaterOrEqual, type, IF_ICMPGE); - } - break; - } - case LessOrEqual lessOrEqual: { - var type = largerType(lessOrEqual.left().type(), lessOrEqual.right().type()); - if (type.equals(TargetType.Long)) { - generateRelationalOperator(state, lessOrEqual, type, LCMP, IFLE); - } else if (type.equals(TargetType.Float)) { - generateRelationalOperator(state, lessOrEqual, type, FCMPL, IFLE); - } else if (type.equals(TargetType.Double)) { - generateRelationalOperator(state, lessOrEqual, type, DCMPL, IFLE); - } else { - generateRelationalOperator(state, lessOrEqual, type, IF_ICMPLE); - } - break; - } - case Equal equal: { - var type = largerType(equal.left().type(), equal.right().type()); - if (type.equals(TargetType.Long)) { - generateRelationalOperator(state, equal, type, LCMP, IFEQ); - } else if (type.equals(TargetType.Float)) { - generateRelationalOperator(state, equal, type, FCMPL, IFEQ); - } else if (type.equals(TargetType.Double)) { - generateRelationalOperator(state, equal, type, DCMPL, IFEQ); - } else if (type.equals(TargetType.Char) - || type.equals(TargetType.Short) - || type.equals(TargetType.Byte) - || type.equals(TargetType.Integer) - || type.equals(TargetType.Boolean)) { - generateRelationalOperator(state, equal, type, IF_ICMPEQ); - } else { - generateRelationalOperator(state, equal, type, IF_ACMPEQ); - } - break; - } - case NotEqual notEqual: { - var type = largerType(notEqual.left().type(), notEqual.right().type()); - if (type.equals(TargetType.Long)) { - generateRelationalOperator(state, notEqual, type, LCMP, IFNE); - } else if (type.equals(TargetType.Float)) { - generateRelationalOperator(state, notEqual, type, FCMPL, IFNE); - } else if (type.equals(TargetType.Double)) { - generateRelationalOperator(state, notEqual, type, DCMPL, IFNE); - } else if (type.equals(TargetType.Char) - || type.equals(TargetType.Short) - || type.equals(TargetType.Byte) - || type.equals(TargetType.Integer)) { - generateRelationalOperator(state, notEqual, type, IF_ICMPNE); - } else { - generateRelationalOperator(state, notEqual, type, IF_ACMPNE); - } - break; + break; + } + case NotEqual notEqual: { + var type = largerType(notEqual.left().type(), notEqual.right().type()); + if (type.equals(TargetType.Long)) { + generateRelationalOperator(state, notEqual, type, LCMP, IFNE); + } else if (type.equals(TargetType.Float)) { + generateRelationalOperator(state, notEqual, type, FCMPL, IFNE); + } else if (type.equals(TargetType.Double)) { + generateRelationalOperator(state, notEqual, type, DCMPL, IFNE); + } else if (type.equals(TargetType.Char) || type.equals(TargetType.Short) || type.equals(TargetType.Byte) || type.equals(TargetType.Integer)) { + generateRelationalOperator(state, notEqual, type, IF_ICMPNE); + } else { + generateRelationalOperator(state, notEqual, type, IF_ACMPNE); } + break; + } } } @@ -588,118 +564,119 @@ public class Codegen { private void generateUnaryOp(State state, TargetUnaryOp op) { var mv = state.mv; switch (op) { - case TargetUnaryOp.Add add: - // This literally does nothing - generate(state, add.expr()); - break; - case TargetUnaryOp.Negate negate: - generate(state, negate.expr()); - if (negate.type().equals(TargetType.Double)) - mv.visitInsn(DNEG); - else if (negate.type().equals(TargetType.Float)) - mv.visitInsn(FNEG); - else if (negate.type().equals(TargetType.Long)) - mv.visitInsn(LNEG); - else mv.visitInsn(INEG); - break; - case TargetUnaryOp.Not not: - generate(state, not.expr()); - if (not.type().equals(TargetType.Long)) { - mv.visitLdcInsn(-1L); - mv.visitInsn(LXOR); - } else { - mv.visitInsn(ICONST_M1); - mv.visitInsn(IXOR); - } - break; - case TargetUnaryOp.PreIncrement preIncrement: - generate(state, preIncrement.expr()); - if (preIncrement.type().equals(TargetType.Float)) { - mv.visitLdcInsn(1F); - mv.visitInsn(FADD); - mv.visitInsn(DUP); - } else if (preIncrement.type().equals(TargetType.Double)) { - mv.visitLdcInsn(1D); - mv.visitInsn(DADD); - mv.visitInsn(DUP2); - } else if (preIncrement.type().equals(TargetType.Long)) { - mv.visitLdcInsn(1L); - mv.visitInsn(LADD); - mv.visitInsn(DUP2); - } else { - mv.visitLdcInsn(1); - mv.visitInsn(IADD); - mv.visitInsn(DUP); - } - boxPrimitive(state, preIncrement.type()); - afterIncDec(state, preIncrement); - break; - case TargetUnaryOp.PreDecrement preDecrement: - generate(state, preDecrement.expr()); - if (preDecrement.type().equals(TargetType.Float)) { - mv.visitLdcInsn(1F); - mv.visitInsn(FSUB); - mv.visitInsn(DUP); - } else if (preDecrement.type().equals(TargetType.Double)) { - mv.visitLdcInsn(1D); - mv.visitInsn(DSUB); - mv.visitInsn(DUP2); - } else if (preDecrement.type().equals(TargetType.Long)) { - mv.visitLdcInsn(1L); - mv.visitInsn(LSUB); - mv.visitInsn(DUP2); - } else { - mv.visitLdcInsn(1); - mv.visitInsn(ISUB); - mv.visitInsn(DUP); - } - boxPrimitive(state, preDecrement.type()); - afterIncDec(state, preDecrement); - break; - case TargetUnaryOp.PostIncrement postIncrement: - generate(state, postIncrement.expr()); - if (postIncrement.type().equals(TargetType.Float)) { - mv.visitInsn(DUP); - mv.visitLdcInsn(1F); - mv.visitInsn(FADD); - } else if (postIncrement.type().equals(TargetType.Double)) { - mv.visitInsn(DUP2); - mv.visitLdcInsn(1D); - mv.visitInsn(DADD); - } else if (postIncrement.type().equals(TargetType.Long)) { - mv.visitInsn(DUP2); - mv.visitLdcInsn(1L); - mv.visitInsn(LADD); - } else { - mv.visitInsn(DUP); - mv.visitLdcInsn(1); - mv.visitInsn(IADD); - } - boxPrimitive(state, postIncrement.type()); - afterIncDec(state, postIncrement); - break; - case TargetUnaryOp.PostDecrement postDecrement: - generate(state, postDecrement.expr()); - if (postDecrement.type().equals(TargetType.Float)) { - mv.visitInsn(DUP); - mv.visitLdcInsn(1F); - mv.visitInsn(FSUB); - } else if (postDecrement.type().equals(TargetType.Double)) { - mv.visitInsn(DUP2); - mv.visitLdcInsn(1D); - mv.visitInsn(DSUB); - } else if (postDecrement.type().equals(TargetType.Long)) { - mv.visitInsn(DUP2); - mv.visitLdcInsn(1L); - mv.visitInsn(LSUB); - } else { - mv.visitInsn(DUP); - mv.visitLdcInsn(1); - mv.visitInsn(ISUB); - } - boxPrimitive(state, postDecrement.type()); - afterIncDec(state, postDecrement); - break; + case TargetUnaryOp.Add add: + // This literally does nothing + generate(state, add.expr()); + break; + case TargetUnaryOp.Negate negate: + generate(state, negate.expr()); + if (negate.type().equals(TargetType.Double)) + mv.visitInsn(DNEG); + else if (negate.type().equals(TargetType.Float)) + mv.visitInsn(FNEG); + else if (negate.type().equals(TargetType.Long)) + mv.visitInsn(LNEG); + else + mv.visitInsn(INEG); + break; + case TargetUnaryOp.Not not: + generate(state, not.expr()); + if (not.type().equals(TargetType.Long)) { + mv.visitLdcInsn(-1L); + mv.visitInsn(LXOR); + } else { + mv.visitInsn(ICONST_M1); + mv.visitInsn(IXOR); + } + break; + case TargetUnaryOp.PreIncrement preIncrement: + generate(state, preIncrement.expr()); + if (preIncrement.type().equals(TargetType.Float)) { + mv.visitLdcInsn(1F); + mv.visitInsn(FADD); + mv.visitInsn(DUP); + } else if (preIncrement.type().equals(TargetType.Double)) { + mv.visitLdcInsn(1D); + mv.visitInsn(DADD); + mv.visitInsn(DUP2); + } else if (preIncrement.type().equals(TargetType.Long)) { + mv.visitLdcInsn(1L); + mv.visitInsn(LADD); + mv.visitInsn(DUP2); + } else { + mv.visitLdcInsn(1); + mv.visitInsn(IADD); + mv.visitInsn(DUP); + } + boxPrimitive(state, preIncrement.type()); + afterIncDec(state, preIncrement); + break; + case TargetUnaryOp.PreDecrement preDecrement: + generate(state, preDecrement.expr()); + if (preDecrement.type().equals(TargetType.Float)) { + mv.visitLdcInsn(1F); + mv.visitInsn(FSUB); + mv.visitInsn(DUP); + } else if (preDecrement.type().equals(TargetType.Double)) { + mv.visitLdcInsn(1D); + mv.visitInsn(DSUB); + mv.visitInsn(DUP2); + } else if (preDecrement.type().equals(TargetType.Long)) { + mv.visitLdcInsn(1L); + mv.visitInsn(LSUB); + mv.visitInsn(DUP2); + } else { + mv.visitLdcInsn(1); + mv.visitInsn(ISUB); + mv.visitInsn(DUP); + } + boxPrimitive(state, preDecrement.type()); + afterIncDec(state, preDecrement); + break; + case TargetUnaryOp.PostIncrement postIncrement: + generate(state, postIncrement.expr()); + if (postIncrement.type().equals(TargetType.Float)) { + mv.visitInsn(DUP); + mv.visitLdcInsn(1F); + mv.visitInsn(FADD); + } else if (postIncrement.type().equals(TargetType.Double)) { + mv.visitInsn(DUP2); + mv.visitLdcInsn(1D); + mv.visitInsn(DADD); + } else if (postIncrement.type().equals(TargetType.Long)) { + mv.visitInsn(DUP2); + mv.visitLdcInsn(1L); + mv.visitInsn(LADD); + } else { + mv.visitInsn(DUP); + mv.visitLdcInsn(1); + mv.visitInsn(IADD); + } + boxPrimitive(state, postIncrement.type()); + afterIncDec(state, postIncrement); + break; + case TargetUnaryOp.PostDecrement postDecrement: + generate(state, postDecrement.expr()); + if (postDecrement.type().equals(TargetType.Float)) { + mv.visitInsn(DUP); + mv.visitLdcInsn(1F); + mv.visitInsn(FSUB); + } else if (postDecrement.type().equals(TargetType.Double)) { + mv.visitInsn(DUP2); + mv.visitLdcInsn(1D); + mv.visitInsn(DSUB); + } else if (postDecrement.type().equals(TargetType.Long)) { + mv.visitInsn(DUP2); + mv.visitLdcInsn(1L); + mv.visitInsn(LSUB); + } else { + mv.visitInsn(DUP); + mv.visitLdcInsn(1); + mv.visitInsn(ISUB); + } + boxPrimitive(state, postDecrement.type()); + afterIncDec(state, postDecrement); + break; } } @@ -712,29 +689,17 @@ public class Codegen { } else { var name = "lambda$" + lambdaCounter++; var parameters = new ArrayList<>(lambda.captures()); - parameters.addAll(lambda.params().stream() - .map(param -> param.type() instanceof TargetGenericType ? new MethodParameter(TargetType.Object, param.name()) : param) - .toList()); + parameters.addAll(lambda.params().stream().map(param -> param.type() instanceof TargetGenericType ? new MethodParameter(TargetType.Object, param.name()) : param).toList()); - impl = new TargetMethod( - 0, name, Set.of(), Set.of(), - parameters, - lambda.returnType() instanceof TargetGenericType ? TargetType.Object : lambda.returnType(), - lambda.block() - ); + impl = new TargetMethod(0, name, Set.of(), Set.of(), parameters, lambda.returnType() instanceof TargetGenericType ? TargetType.Object : lambda.returnType(), lambda.block()); generateMethod(impl); lambdas.put(lambda, impl); } - var mt = MethodType.methodType(CallSite.class, MethodHandles.Lookup.class, String.class, - MethodType.class, MethodType.class, MethodHandle.class, MethodType.class); + var mt = MethodType.methodType(CallSite.class, MethodHandles.Lookup.class, String.class, MethodType.class, MethodType.class, MethodHandle.class, MethodType.class); - var bootstrap = new Handle(H_INVOKESTATIC, "java/lang/invoke/LambdaMetafactory", "metafactory", - mt.toMethodDescriptorString(), false); - var handle = new Handle( - H_INVOKEVIRTUAL, clazz.getName(), impl.name(), - impl.getDescriptor(), false - ); + var bootstrap = new Handle(H_INVOKESTATIC, "java/lang/invoke/LambdaMetafactory", "metafactory", mt.toMethodDescriptorString(), false); + var handle = new Handle(H_INVOKEVIRTUAL, clazz.getName(), impl.name(), impl.getDescriptor(), false); // TODO maybe make this a function? var desugared = "("; @@ -743,249 +708,245 @@ public class Codegen { desugared += ")"; if (lambda.returnType() != null) desugared += "Ljava/lang/Object;"; - else desugared += "V"; + else + desugared += "V"; var params = new ArrayList(); params.add(new TargetRefType(clazz.qualifiedName())); - params.addAll(lambda.captures().stream() - .map(MethodParameter::type) - .toList()); + params.addAll(lambda.captures().stream().map(MethodParameter::type).toList()); var descriptor = TargetMethod.getDescriptor(lambda.type(), params.toArray(TargetType[]::new)); mv.visitVarInsn(ALOAD, 0); for (var capture : lambda.captures()) mv.visitVarInsn(ALOAD, state.scope.get(capture.name()).index); - mv.visitInvokeDynamicInsn("apply", descriptor, - bootstrap, Type.getType(desugared), handle, - Type.getType(TargetMethod.getDescriptor(impl.returnType(), lambda.params().stream().map(MethodParameter::type).toArray(TargetType[]::new))) - ); + mv.visitInvokeDynamicInsn("apply", descriptor, bootstrap, Type.getType(desugared), handle, Type.getType(TargetMethod.getDescriptor(impl.returnType(), lambda.params().stream().map(MethodParameter::type).toArray(TargetType[]::new)))); } private void generate(State state, TargetExpression expr) { var mv = state.mv; switch (expr) { - case TargetClassName ignored: - break; // NOP - case TargetBlock block: { - var localCounter = state.localCounter; - state.enterScope(); - for (var e : block.statements()) { - generate(state, e); - if (e instanceof TargetMethodCall) { - if (e.type() != null) popValue(state, e.type()); - } else if (e instanceof TargetAssign) { - mv.visitInsn(POP); // TODO Nasty fix, we don't know if it is a primitive double or long - } else if (e instanceof TargetStatementExpression se) { - popValue(state, se.type()); - } + case TargetClassName ignored: + break; // NOP + case TargetBlock block: { + var localCounter = state.localCounter; + state.enterScope(); + for (var e : block.statements()) { + generate(state, e); + if (e instanceof TargetMethodCall) { + if (e.type() != null) + popValue(state, e.type()); + } else if (e instanceof TargetAssign) { + mv.visitInsn(POP); // TODO Nasty fix, we don't know if it is a primitive double or long + } else if (e instanceof TargetStatementExpression se) { + popValue(state, se.type()); } - state.exitScope(); - state.localCounter = localCounter; - break; } - case TargetCast cast: - generate(state, cast.expr()); - convertTo(state, cast.expr().type(), cast.type()); + state.exitScope(); + state.localCounter = localCounter; + break; + } + case TargetCast cast: + generate(state, cast.expr()); + convertTo(state, cast.expr().type(), cast.type()); + break; + case TargetInstanceOf instanceOf: + mv.visitTypeInsn(INSTANCEOF, instanceOf.right().getInternalName()); + break; + case TargetLiteral literal: + switch (literal) { + case IntLiteral intLiteral: + mv.visitLdcInsn(intLiteral.value()); break; - case TargetInstanceOf instanceOf: - mv.visitTypeInsn(INSTANCEOF, instanceOf.right().getInternalName()); + case FloatLiteral floatLiteral: + mv.visitLdcInsn(floatLiteral.value()); break; - case TargetLiteral literal: - switch (literal) { - case IntLiteral intLiteral: - mv.visitLdcInsn(intLiteral.value()); - break; - case FloatLiteral floatLiteral: - mv.visitLdcInsn(floatLiteral.value()); - break; - case LongLiteral longLiteral: - mv.visitLdcInsn(longLiteral.value()); - break; - case StringLiteral stringLiteral: - mv.visitLdcInsn(stringLiteral.value()); - break; - case CharLiteral charLiteral: - mv.visitIntInsn(BIPUSH, charLiteral.value()); - break; - case DoubleLiteral doubleLiteral: - mv.visitLdcInsn(doubleLiteral.value()); - break; - case BooleanLiteral booleanLiteral: - if (booleanLiteral.value()) { - mv.visitInsn(ICONST_1); - } else { - mv.visitInsn(ICONST_0); - } - break; - } + case LongLiteral longLiteral: + mv.visitLdcInsn(longLiteral.value()); break; - case TargetVarDecl varDecl: { - var local = state.createVariable(varDecl.name(), varDecl.varType()); - if (varDecl.value() != null) { - generate(state, varDecl.value()); - boxPrimitive(state, varDecl.varType()); - mv.visitVarInsn(ASTORE, local.index()); + case StringLiteral stringLiteral: + mv.visitLdcInsn(stringLiteral.value()); + break; + case CharLiteral charLiteral: + mv.visitIntInsn(BIPUSH, charLiteral.value()); + break; + case DoubleLiteral doubleLiteral: + mv.visitLdcInsn(doubleLiteral.value()); + break; + case BooleanLiteral booleanLiteral: + if (booleanLiteral.value()) { + mv.visitInsn(ICONST_1); } else { - mv.visitInsn(ACONST_NULL); - mv.visitVarInsn(ASTORE, local.index()); + mv.visitInsn(ICONST_0); } break; } - case TargetBinaryOp op: - generateBinaryOp(state, op); - break; - case TargetUnaryOp op: - generateUnaryOp(state, op); - break; - case TargetAssign assign: { - switch (assign.left()) { - case TargetLocalVar localVar: { - generate(state, assign.right()); - boxPrimitive(state, assign.right().type()); - var local = state.scope.get(localVar.name()); - mv.visitInsn(DUP); - mv.visitVarInsn(ASTORE, local.index()); - break; - } - case TargetFieldVar dot: { - var fieldType = dot.type(); - generate(state, dot.left()); - generate(state, assign.right()); - convertTo(state, assign.right().type(), fieldType); - boxPrimitive(state, fieldType); - if (dot.isStatic()) - mv.visitInsn(DUP); - else mv.visitInsn(DUP_X1); - mv.visitFieldInsn(dot.isStatic() ? PUTSTATIC : PUTFIELD, dot.owner().getInternalName(), dot.right(), fieldType.toSignature()); - break; - } - default: - throw new CodeGenException("Invalid assignment"); - } - break; + break; + case TargetVarDecl varDecl: { + var local = state.createVariable(varDecl.name(), varDecl.varType()); + if (varDecl.value() != null) { + generate(state, varDecl.value()); + boxPrimitive(state, varDecl.varType()); + mv.visitVarInsn(ASTORE, local.index()); + } else { + mv.visitInsn(ACONST_NULL); + mv.visitVarInsn(ASTORE, local.index()); } + break; + } + case TargetBinaryOp op: + generateBinaryOp(state, op); + break; + case TargetUnaryOp op: + generateUnaryOp(state, op); + break; + case TargetAssign assign: { + switch (assign.left()) { case TargetLocalVar localVar: { - LocalVar local = state.scope.get(localVar.name()); - mv.visitVarInsn(ALOAD, local.index()); - unboxPrimitive(state, local.type()); + generate(state, assign.right()); + boxPrimitive(state, assign.right().type()); + var local = state.scope.get(localVar.name()); + mv.visitInsn(DUP); + mv.visitVarInsn(ASTORE, local.index()); break; } case TargetFieldVar dot: { - if (!dot.isStatic()) - generate(state, dot.left()); - mv.visitFieldInsn(dot.isStatic() ? GETSTATIC : GETFIELD, dot.left().type().getInternalName(), dot.right(), dot.type().toSignature()); - unboxPrimitive(state, dot.type()); - break; - } - case TargetFor _for: { - state.enterScope(); - var localCounter = state.localCounter; - if (_for.init() != null) - generate(state, _for.init()); - Label start = new Label(); - Label end = new Label(); - mv.visitLabel(start); - if (_for.termination() != null) - generate(state, _for.termination()); - else mv.visitInsn(ICONST_1); - mv.visitJumpInsn(IFEQ, end); - generate(state, _for.body()); - if (_for.increment() != null) { - generate(state, _for.increment()); - if (_for.increment().type() != null) { - popValue(state, _for.increment().type()); - } - } - mv.visitJumpInsn(GOTO, start); - mv.visitLabel(end); - state.exitScope(); - state.localCounter = localCounter; - break; - } - case TargetWhile _while: { - Label start = new Label(); - Label end = new Label(); - mv.visitLabel(start); - generate(state, _while.cond()); - mv.visitJumpInsn(IFEQ, end); - generate(state, _while.body()); - mv.visitJumpInsn(GOTO, start); - mv.visitLabel(end); - break; - } - case TargetIf _if: { - generate(state, _if.cond()); - Label _else = new Label(); - Label end = new Label(); - mv.visitJumpInsn(IFEQ, _else); - generate(state, _if.if_body()); - mv.visitJumpInsn(GOTO, end); - mv.visitLabel(_else); - if (_if.else_body() != null) { - generate(state, _if.else_body()); - } - mv.visitLabel(end); - break; - } - case TargetReturn ret: { - if (ret.expression() != null && state.returnType != null) { - generate(state, ret.expression()); - convertTo(state, ret.expression().type(), state.returnType); - boxPrimitive(state, state.returnType); - mv.visitInsn(ARETURN); - } else mv.visitInsn(RETURN); - break; - } - case TargetThis _this: { - mv.visitVarInsn(ALOAD, 0); - break; - } - case TargetSuper _super: { - mv.visitVarInsn(ALOAD, 0); - break; - } - case TargetMethodCall call: { - generate(state, call.expr()); - for (var i = 0; i < call.args().size(); i++) { - var e = call.args().get(i); - var arg = call.parameterTypes().get(i); - generate(state, e); - if (!(arg instanceof TargetPrimitiveType)) - boxPrimitive(state, e.type()); - } - var descriptor = call.getDescriptor(); - if (call.owner() instanceof TargetFunNType) // Decay FunN - descriptor = TargetMethod.getDescriptor( - call.returnType() == null ? null : TargetType.Object, - call.parameterTypes().stream().map(x -> TargetType.Object).toArray(TargetType[]::new) - ); - - mv.visitMethodInsn(call.isInterface() ? INVOKEINTERFACE : call.isStatic() ? INVOKESTATIC: call.name().equals("") ? INVOKESPECIAL : INVOKEVIRTUAL, - call.owner().getInternalName(), call.name(), descriptor, call.isInterface()); - - if (call.type() != null && call.returnType() != null && !(call.returnType() instanceof TargetPrimitiveType)) { - if (!call.returnType().equals(call.type()) && !(call.type() instanceof TargetGenericType)) - mv.visitTypeInsn(CHECKCAST, call.type().getInternalName()); - unboxPrimitive(state, call.type()); - } - break; - } - case TargetLambdaExpression lambda: - generateLambdaExpression(state, lambda); - break; - case TargetNew _new: { - mv.visitTypeInsn(NEW, _new.type().getInternalName()); - mv.visitInsn(DUP); - for (TargetExpression e : _new.params()) { - generate(state, e); - boxPrimitive(state, e.type()); - } - mv.visitMethodInsn(INVOKESPECIAL, _new.type().getInternalName(), "", _new.getDescriptor(), false); + var fieldType = dot.type(); + generate(state, dot.left()); + generate(state, assign.right()); + convertTo(state, assign.right().type(), fieldType); + boxPrimitive(state, fieldType); + if (dot.isStatic()) + mv.visitInsn(DUP); + else + mv.visitInsn(DUP_X1); + mv.visitFieldInsn(dot.isStatic() ? PUTSTATIC : PUTFIELD, dot.owner().getInternalName(), dot.right(), fieldType.toSignature()); break; } default: - throw new CodeGenException("Unexpected value: " + expr); + throw new CodeGenException("Invalid assignment"); + } + break; + } + case TargetLocalVar localVar: { + LocalVar local = state.scope.get(localVar.name()); + mv.visitVarInsn(ALOAD, local.index()); + unboxPrimitive(state, local.type()); + break; + } + case TargetFieldVar dot: { + if (!dot.isStatic()) + generate(state, dot.left()); + mv.visitFieldInsn(dot.isStatic() ? GETSTATIC : GETFIELD, dot.left().type().getInternalName(), dot.right(), dot.type().toSignature()); + unboxPrimitive(state, dot.type()); + break; + } + case TargetFor _for: { + state.enterScope(); + var localCounter = state.localCounter; + if (_for.init() != null) + generate(state, _for.init()); + Label start = new Label(); + Label end = new Label(); + mv.visitLabel(start); + if (_for.termination() != null) + generate(state, _for.termination()); + else + mv.visitInsn(ICONST_1); + mv.visitJumpInsn(IFEQ, end); + generate(state, _for.body()); + if (_for.increment() != null) { + generate(state, _for.increment()); + if (_for.increment().type() != null) { + popValue(state, _for.increment().type()); + } + } + mv.visitJumpInsn(GOTO, start); + mv.visitLabel(end); + state.exitScope(); + state.localCounter = localCounter; + break; + } + case TargetWhile _while: { + Label start = new Label(); + Label end = new Label(); + mv.visitLabel(start); + generate(state, _while.cond()); + mv.visitJumpInsn(IFEQ, end); + generate(state, _while.body()); + mv.visitJumpInsn(GOTO, start); + mv.visitLabel(end); + break; + } + case TargetIf _if: { + generate(state, _if.cond()); + Label _else = new Label(); + Label end = new Label(); + mv.visitJumpInsn(IFEQ, _else); + generate(state, _if.if_body()); + mv.visitJumpInsn(GOTO, end); + mv.visitLabel(_else); + if (_if.else_body() != null) { + generate(state, _if.else_body()); + } + mv.visitLabel(end); + break; + } + case TargetReturn ret: { + if (ret.expression() != null && state.returnType != null) { + generate(state, ret.expression()); + convertTo(state, ret.expression().type(), state.returnType); + boxPrimitive(state, state.returnType); + mv.visitInsn(ARETURN); + } else + mv.visitInsn(RETURN); + break; + } + case TargetThis _this: { + mv.visitVarInsn(ALOAD, 0); + break; + } + case TargetSuper _super: { + mv.visitVarInsn(ALOAD, 0); + break; + } + case TargetMethodCall call: { + generate(state, call.expr()); + for (var i = 0; i < call.args().size(); i++) { + var e = call.args().get(i); + var arg = call.parameterTypes().get(i); + generate(state, e); + if (!(arg instanceof TargetPrimitiveType)) + boxPrimitive(state, e.type()); + } + var descriptor = call.getDescriptor(); + if (call.owner() instanceof TargetFunNType) // Decay FunN + descriptor = TargetMethod.getDescriptor(call.returnType() == null ? null : TargetType.Object, call.parameterTypes().stream().map(x -> TargetType.Object).toArray(TargetType[]::new)); + + mv.visitMethodInsn(call.isInterface() ? INVOKEINTERFACE : call.isStatic() ? INVOKESTATIC : call.name().equals("") ? INVOKESPECIAL : INVOKEVIRTUAL, call.owner().getInternalName(), call.name(), descriptor, call.isInterface()); + + if (call.type() != null && call.returnType() != null && !(call.returnType() instanceof TargetPrimitiveType)) { + if (!call.returnType().equals(call.type()) && !(call.type() instanceof TargetGenericType)) + mv.visitTypeInsn(CHECKCAST, call.type().getInternalName()); + unboxPrimitive(state, call.type()); + } + break; + } + case TargetLambdaExpression lambda: + generateLambdaExpression(state, lambda); + break; + case TargetNew _new: { + mv.visitTypeInsn(NEW, _new.type().getInternalName()); + mv.visitInsn(DUP); + for (TargetExpression e : _new.params()) { + generate(state, e); + boxPrimitive(state, e.type()); + } + mv.visitMethodInsn(INVOKESPECIAL, _new.type().getInternalName(), "", _new.getDescriptor(), false); + break; + } + default: + throw new CodeGenException("Unexpected value: " + expr); } } @@ -1000,7 +961,7 @@ public class Codegen { mv.visitCode(); var state = new State(null, mv, 1); - for (var param: constructor.parameters()) + for (var param : constructor.parameters()) state.createVariable(param.name(), param.type()); var stmts = constructor.block().statements(); @@ -1027,7 +988,7 @@ public class Codegen { mv.visitCode(); var state = new State(method.returnType(), mv, method.isStatic() ? 0 : 1); - for (var param: method.parameters()) + for (var param : method.parameters()) state.createVariable(param.name(), param.type()); generate(state, method.block()); if (method.returnType() == null) @@ -1048,10 +1009,7 @@ public class Codegen { } public byte[] generate() { - cw.visit(V1_8, clazz.modifiers() | ACC_PUBLIC | ACC_SUPER, clazz.qualifiedName(), - generateSignature(clazz, clazz.generics()), clazz.superType() != null ? clazz.superType().getInternalName(): "java/lang/Object", - clazz.implementingInterfaces().stream().map(TargetType::toSignature).toArray(String[]::new) - ); + cw.visit(V1_8, clazz.modifiers() | ACC_PUBLIC | ACC_SUPER, clazz.qualifiedName(), generateSignature(clazz, clazz.generics()), clazz.superType() != null ? clazz.superType().getInternalName() : "java/lang/Object", clazz.implementingInterfaces().stream().map(TargetType::toSignature).toArray(String[]::new)); if (!clazz.txGenerics().isEmpty()) cw.visitAttribute(new JavaTXSignatureAttribute(generateSignature(clazz, clazz.txGenerics()))); diff --git a/src/main/java/de/dhbwstuttgart/parser/SyntaxTreeGenerator/StatementGenerator.java b/src/main/java/de/dhbwstuttgart/parser/SyntaxTreeGenerator/StatementGenerator.java index 8a3d8ec6..d4e645d1 100644 --- a/src/main/java/de/dhbwstuttgart/parser/SyntaxTreeGenerator/StatementGenerator.java +++ b/src/main/java/de/dhbwstuttgart/parser/SyntaxTreeGenerator/StatementGenerator.java @@ -122,17 +122,15 @@ public class StatementGenerator { public ParameterList convert(Java17Parser.FormalParameterListContext formalParameterListContext) { List ret = new ArrayList<>(); List fps = new ArrayList<>(); - if (formalParameterListContext == null || formalParameterListContext.lastFormalParameter() == null) + if (!Objects.isNull(formalParameterListContext.lastFormalParameter())) { + /* + * Der '...' Operator wird noch nicht unterstützt, da dafür benötigte Typen (List oder Array) nicht vom Typinferenzalgo. verarbeitet werden können + */ + throw new NotImplementedException("Formale Parameter variabler Länge nicht unterstützt."); + } + if (formalParameterListContext.children.size() == 0) return new ParameterList(ret, new NullToken()); // Dann ist die Parameterliste leer - - /* - * Restrukturierung Java17-Grammatik Zeile wird nicht mehr benötigt, da Regel für Parameter-Liste nicht mehr rekursiv ist. "lastFormalParameter" hat kein Kind "formalParameter" mehr. - * - * if(formalParameterListContext.lastFormalParameter().formalParameter() == null) throw new NotImplementedException(); - */ - fps = formalParameterListContext.formalParameter(); - for (Java17Parser.FormalParameterContext fp : fps) { String paramName = SyntaxTreeGenerator.convert(fp.variableDeclaratorId()); RefTypeOrTPHOrWildcardOrGeneric type; diff --git a/src/main/java/de/dhbwstuttgart/target/generate/StatementToTargetExpression.java b/src/main/java/de/dhbwstuttgart/target/generate/StatementToTargetExpression.java index a5c4d644..62e68843 100644 --- a/src/main/java/de/dhbwstuttgart/target/generate/StatementToTargetExpression.java +++ b/src/main/java/de/dhbwstuttgart/target/generate/StatementToTargetExpression.java @@ -206,7 +206,7 @@ public class StatementToTargetExpression implements StatementVisitor { var returnType = isFunNType ? TargetType.Object : converter.convert(methodCall.signature.get(methodCall.signature.size() - 1)); var receiverName = new JavaClassName(converter.convert(methodCall.receiver.getType()).name()); var argList = methodCall.signature.stream().map(converter::convert).toList(); - argList = argList.subList(0, argList.size() - 1); + // argList = argList.subList(0, argList.size() - 1); Method foundMethod = null; if (methodCall.receiver instanceof ExpressionReceiver expressionReceiver && expressionReceiver.expr instanceof This) { diff --git a/src/test/java/targetast/TestComplete.java b/src/test/java/targetast/TestComplete.java index b8fc0b8d..5b78b382 100644 --- a/src/test/java/targetast/TestComplete.java +++ b/src/test/java/targetast/TestComplete.java @@ -206,7 +206,7 @@ public class TestComplete { vv1.addElement(v3); vv1.addElement(v4); - var instanceOfClass_m2 = matrixOP.getDeclaredConstructor(Vector.class).newInstance(vv1);//Matrix m2 = new Matrix(vv1); + var instanceOfClass_m2 = matrixOP.getDeclaredConstructor(Vector.class).newInstance(vv1);// Matrix m2 = new Matrix(vv1); var mul = matrixOP.getField("mul"); mul.setAccessible(true); @@ -238,10 +238,10 @@ public class TestComplete { var matrix = classFiles.get("Matrix"); Vector> vv = new Vector<>(); - Vector v1 = new Vector<> (); + Vector v1 = new Vector<>(); v1.addElement(2); v1.addElement(2); - Vector v2 = new Vector<> (); + Vector v2 = new Vector<>(); v2.addElement(3); v2.addElement(3); vv.addElement(v1); @@ -250,10 +250,10 @@ public class TestComplete { var instanceOfClass_m1 = matrix.getDeclaredConstructor(Vector.class).newInstance(vv); Vector> vv1 = new Vector<>(); - Vector v3 = new Vector<> (); + Vector v3 = new Vector<>(); v3.addElement(2); v3.addElement(2); - Vector v4 = new Vector<> (); + Vector v4 = new Vector<>(); v4.addElement(3); v4.addElement(3); vv1.addElement(v3); @@ -266,10 +266,10 @@ public class TestComplete { System.out.println(instanceOfClass_m1.toString() + " * " + instanceOfClass_m2.toString() + " = " + result.toString()); Vector> res = new Vector<>(); - Vector v5 = new Vector<> (); + Vector v5 = new Vector<>(); v5.addElement(10); v5.addElement(10); - Vector v6 = new Vector<> (); + Vector v6 = new Vector<>(); v6.addElement(15); v6.addElement(15); res.addElement(v5); @@ -324,7 +324,7 @@ public class TestComplete { var relOps = classFiles.get("RelOps"); var instance = relOps.getDeclaredConstructor().newInstance(); - var m = relOps.getDeclaredMethod("m", Integer.class,Integer.class); + var m = relOps.getDeclaredMethod("m", Integer.class, Integer.class); assertFalse((Boolean) m.invoke(instance, 7, 3)); } @@ -339,7 +339,7 @@ public class TestComplete { var classFiles = generateClassFiles("SubMatrix.jav", new ByteArrayClassLoader()); var instance = classFiles.get("SubMatrix").getDeclaredConstructor().newInstance(); } - + @Test public void tphTest() throws Exception { var classFiles = generateClassFiles("Tph.jav", new ByteArrayClassLoader()); @@ -487,7 +487,6 @@ public class TestComplete { assertEquals(W, m2.getGenericReturnType()); } - @Test public void Tph7Test() throws Exception { var classFiles = TestCodegen.generateClassFiles("Tph7.jav", new ByteArrayClassLoader()); @@ -497,59 +496,55 @@ public class TestComplete { // public N m(O var1, N var2) Method m = classToTest.getDeclaredMethod("m", Object.class, Object.class); - //System.out.println(m.toString()); + // System.out.println(m.toString()); - //Argumenttypes of the method m + // Argumenttypes of the method m var paraTypes = m.getGenericParameterTypes(); - //Typeparameters of the method m - var typeParaTypes = m.getTypeParameters(); + // Typeparameters of the method m + var typeParaTypes = m.getTypeParameters(); - //Typeparameters are extracted from the argumenttypes - //Conditions for the extracted typeparameters are set + // Typeparameters are extracted from the argumenttypes + // Conditions for the extracted typeparameters are set - //paraTypes[0] = O - var boundFstArg = Arrays.stream(typeParaTypes) - .filter(x -> x.equals(paraTypes[0])).findFirst().get().getBounds(); + // paraTypes[0] = O + var boundFstArg = Arrays.stream(typeParaTypes).filter(x -> x.equals(paraTypes[0])).findFirst().get().getBounds(); - //Bound of O has to be Object + // Bound of O has to be Object assertEquals(Object.class, Arrays.stream(boundFstArg).findFirst().get()); - //paraTypes[1] = N - var N = Arrays.stream(typeParaTypes) - .filter(x -> x.equals(paraTypes[1])).findFirst().get(); + // paraTypes[1] = N + var N = Arrays.stream(typeParaTypes).filter(x -> x.equals(paraTypes[1])).findFirst().get(); var boundSndArg = N.getBounds(); - //Bound of H has to be Object + // Bound of H has to be Object assertEquals(Object.class, Arrays.stream(boundSndArg).findFirst().get()); - //N has to be the return type of m + // N has to be the return type of m assertEquals(N, m.getGenericReturnType()); - //public DZU m2(DZU); + // public DZU m2(DZU); Method m2 = classToTest.getDeclaredMethod("m2", Object.class); - //Argumenttypes of the method m2 + // Argumenttypes of the method m2 var paraTypesm2 = m2.getGenericParameterTypes(); - //Typeparameters of the method m2 - var typeParaTypesm2 = m2.getTypeParameters(); + // Typeparameters of the method m2 + var typeParaTypesm2 = m2.getTypeParameters(); - //Typeparameters are extracted from the argumenttypes - //Conditions for the extracted typeparameters are set + // Typeparameters are extracted from the argumenttypes + // Conditions for the extracted typeparameters are set - //paraTypes[0] = DZU - var fstArgm2 = Arrays.stream(typeParaTypesm2) - .filter(x -> x.equals(paraTypesm2[0])).findFirst().get(); + // paraTypes[0] = DZU + var fstArgm2 = Arrays.stream(typeParaTypesm2).filter(x -> x.equals(paraTypesm2[0])).findFirst().get(); - //Bound of DZU has to be Object + // Bound of DZU has to be Object assertEquals(Object.class, Arrays.stream(fstArgm2.getBounds()).findFirst().get()); - //DZU has to be the return type of m + // DZU has to be the return type of m assertEquals(fstArgm2, m2.getGenericReturnType()); } - @Test public void typedIdTest() throws Exception { var classFiles = generateClassFiles("TypedID.jav", new ByteArrayClassLoader());