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
+ 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());