Compare commits

..

1 Commits

Author SHA1 Message Date
Ruben
e1007cce30 return error Message String
All checks were successful
Build and Test with Maven / Build-and-test-with-Maven (push) Successful in 1m29s
2025-09-26 09:33:31 +02:00
22 changed files with 211 additions and 402 deletions

View File

@@ -18,7 +18,7 @@ jobs:
uses: actions/setup-java@v4 uses: actions/setup-java@v4
with: with:
distribution: 'temurin' distribution: 'temurin'
java-version: '25' java-version: '24'
cache: 'maven' cache: 'maven'
- name: Compile project - name: Compile project
run: | run: |

View File

@@ -24,7 +24,7 @@ jobs:
uses: actions/setup-java@v4 uses: actions/setup-java@v4
with: with:
distribution: 'temurin' distribution: 'temurin'
java-version: '25' java-version: '24'
cache: 'maven' cache: 'maven'
- name: Compile project - name: Compile project
run: | run: |

10
pom.xml
View File

@@ -44,11 +44,6 @@ http://maven.apache.org/maven-v4_0_0.xsd">
<artifactId>asm</artifactId> <artifactId>asm</artifactId>
<version>9.8</version> <version>9.8</version>
</dependency> </dependency>
<dependency>
<groupId>org.ow2.asm</groupId>
<artifactId>asm-util</artifactId>
<version>9.8</version>
</dependency>
</dependencies> </dependencies>
<build> <build>
@@ -77,8 +72,9 @@ http://maven.apache.org/maven-v4_0_0.xsd">
<artifactId>maven-compiler-plugin</artifactId> <artifactId>maven-compiler-plugin</artifactId>
<version>3.14.0</version> <version>3.14.0</version>
<configuration> <configuration>
<source>25</source> <compilerArgs>--enable-preview</compilerArgs>
<target>25</target> <source>24</source>
<target>24</target>
</configuration> </configuration>
</plugin> </plugin>
<plugin> <plugin>

View File

@@ -1,3 +0,0 @@
class Bug378Id {
id2 = x -> x;
}

View File

@@ -1,8 +0,0 @@
import Bug378Id;
import java.lang.Integer;
public class Bug378Main {
public static main(args) {
var hallo = (new Bug378Id<Integer>().id2).apply(1);
}
}

View File

@@ -1,24 +0,0 @@
import java.lang.Integer;
import java.lang.Double;
import java.lang.System;
import java.io.PrintStream;
public class Bug379 {
public Fun1$$<Double, Double> fact = (x) -> {
if (x == 1) {
return 1;
} else {
return x * (fact.apply(x-1));
}
};
public getFact(x) {
return fact.apply(x);
}
public static void main(x) {
var f = new Bug379();
var intRes = f.getFact(3);
System.out.println(intRes);
}
}

View File

@@ -1,12 +0,0 @@
sealed interface List<T> permits Cons, Empty {}
record Cons<T>(T a , List<T> l ) implements List <T> {}
record Empty<T>() implements List <T> {}
public class Bug380 {
public <T> List<T> append(l1, List<T> l2) {
return switch ( l1 ) {
case Cons(e, rest) -> new Cons<>(e, append(rest, l2)); //::Typ TPH A
case Empty() -> l2;//::TPH B
};
}
}

View File

@@ -1,13 +0,0 @@
import java.lang.Runnable;
import java.lang.String;
import java.lang.System;
import java.io.PrintStream;
import java.lang.Thread;
public class Bug382 {
public static main(a) {
var f = () -> System.out.println("Hallo Welt!");
new Thread(f).run();
}
}

View File

@@ -1,10 +0,0 @@
import java.lang.String;
import java.lang.System;
import java.io.PrintStream;
public class Bug383 {
public static main(a) {
var f = () -> System.out.println("Hello from Thread!");
f.apply();
}
}

View File

@@ -1,18 +1,17 @@
import java.lang.Integer; import java.lang.Integer;
import java.lang.Double;
import java.lang.Number;
import java.lang.String; import java.lang.String;
public record R(String n) {} public record R(Number n) {}
public class SwitchOverload { public class SwitchOverload {
f() { return 10; } public f(){}
g() { return 20; }
public m(r) { public m(r) {
return switch(r) { return switch(r) {
case R("test") -> f(); case R("test") -> f();
case R("foo") -> g();
case R r -> 0;
}; };
} }
} }

View File

@@ -9,10 +9,7 @@ import de.dhbwstuttgart.target.tree.*;
import de.dhbwstuttgart.target.tree.expression.*; import de.dhbwstuttgart.target.tree.expression.*;
import de.dhbwstuttgart.target.tree.type.*; import de.dhbwstuttgart.target.tree.type.*;
import org.objectweb.asm.*; import org.objectweb.asm.*;
import org.objectweb.asm.tree.analysis.AnalyzerException;
import org.objectweb.asm.util.CheckClassAdapter;
import java.io.PrintWriter;
import java.lang.invoke.*; import java.lang.invoke.*;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
import java.util.*; import java.util.*;
@@ -128,7 +125,7 @@ public class Codegen {
} }
private void popValue(State state, TargetType type) { private void popValue(State state, TargetType type) {
if (type.equals(TargetType.double_) || type.equals(TargetType.long_)) if (type.equals(TargetType.Double) || type.equals(TargetType.Long))
state.mv.visitInsn(POP2); state.mv.visitInsn(POP2);
else else
state.mv.visitInsn(POP); state.mv.visitInsn(POP);
@@ -137,21 +134,21 @@ public class Codegen {
private void boxPrimitive(State state, TargetType type) { private void boxPrimitive(State state, TargetType type) {
if (type instanceof TargetExtendsWildcard ew) type = ew.innerType(); if (type instanceof TargetExtendsWildcard ew) type = ew.innerType();
var mv = state.mv; var mv = state.mv;
if (type.equals(TargetType.boolean_)) { if (type.equals(TargetType.Boolean) || type.equals(TargetType.boolean_)) {
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;", false); mv.visitMethodInsn(INVOKESTATIC, "java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;", false);
} else if (type.equals(TargetType.byte_)) { } else if (type.equals(TargetType.Byte) || type.equals(TargetType.byte_)) {
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Byte", "valueOf", "(B)Ljava/lang/Byte;", false); mv.visitMethodInsn(INVOKESTATIC, "java/lang/Byte", "valueOf", "(B)Ljava/lang/Byte;", false);
} else if (type.equals(TargetType.double_)) { } else if (type.equals(TargetType.Double) || type.equals(TargetType.double_)) {
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Double", "valueOf", "(D)Ljava/lang/Double;", false); mv.visitMethodInsn(INVOKESTATIC, "java/lang/Double", "valueOf", "(D)Ljava/lang/Double;", false);
} else if (type.equals(TargetType.long_)) { } else if (type.equals(TargetType.Long) || type.equals(TargetType.long_)) {
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Long", "valueOf", "(J)Ljava/lang/Long;", false); mv.visitMethodInsn(INVOKESTATIC, "java/lang/Long", "valueOf", "(J)Ljava/lang/Long;", false);
} else if (type.equals(TargetType.int_)) { } else if (type.equals(TargetType.Integer) || type.equals(TargetType.int_)) {
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;", false); mv.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;", false);
} else if (type.equals(TargetType.float_)) { } else if (type.equals(TargetType.Float) || type.equals(TargetType.float_)) {
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Float", "valueOf", "(F)Ljava/lang/Float;", false); mv.visitMethodInsn(INVOKESTATIC, "java/lang/Float", "valueOf", "(F)Ljava/lang/Float;", false);
} else if (type.equals(TargetType.short_)) { } else if (type.equals(TargetType.Short) || type.equals(TargetType.short_)) {
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Short", "valueOf", "(S)Ljava/lang/Short;", false); mv.visitMethodInsn(INVOKESTATIC, "java/lang/Short", "valueOf", "(S)Ljava/lang/Short;", false);
} else if (type.equals(TargetType.char_)) { } else if (type.equals(TargetType.Char) || type.equals(TargetType.char_)) {
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Character", "valueOf", "(C)Ljava/lang/Character;", false); mv.visitMethodInsn(INVOKESTATIC, "java/lang/Character", "valueOf", "(C)Ljava/lang/Character;", false);
} }
} }
@@ -188,11 +185,9 @@ public class Codegen {
convertTo(state, op.right().type(), type); convertTo(state, op.right().type(), type);
mv.visitJumpInsn(code, if_true); mv.visitJumpInsn(code, if_true);
mv.visitInsn(ICONST_0); mv.visitInsn(ICONST_0);
boxPrimitive(state, TargetType.toPrimitive(op.type()));
mv.visitJumpInsn(GOTO, end); mv.visitJumpInsn(GOTO, end);
mv.visitLabel(if_true); mv.visitLabel(if_true);
mv.visitInsn(ICONST_1); mv.visitInsn(ICONST_1);
boxPrimitive(state, TargetType.toPrimitive(op.type()));
mv.visitLabel(end); mv.visitLabel(end);
} }
@@ -207,11 +202,9 @@ public class Codegen {
mv.visitInsn(cmp); mv.visitInsn(cmp);
mv.visitJumpInsn(code, if_true); mv.visitJumpInsn(code, if_true);
mv.visitInsn(ICONST_0); mv.visitInsn(ICONST_0);
boxPrimitive(state, TargetType.toPrimitive(op.type()));
mv.visitJumpInsn(GOTO, end); mv.visitJumpInsn(GOTO, end);
mv.visitLabel(if_true); mv.visitLabel(if_true);
mv.visitInsn(ICONST_1); mv.visitInsn(ICONST_1);
boxPrimitive(state, TargetType.toPrimitive(op.type()));
mv.visitLabel(end); mv.visitLabel(end);
} }
@@ -240,85 +233,65 @@ public class Codegen {
if (source instanceof TargetExtendsWildcard ew) source = ew.innerType(); if (source instanceof TargetExtendsWildcard ew) source = ew.innerType();
if (dest instanceof TargetExtendsWildcard ew) dest = ew.innerType(); if (dest instanceof TargetExtendsWildcard ew) dest = ew.innerType();
var mv = state.mv;
if (source.equals(dest)) if (source.equals(dest))
return; return;
if (source.equals(TargetType.Long)) {
if (isFunctionalInterface(source) && isFunctionalInterface(dest) && if (dest.equals(TargetType.Integer))
mv.visitInsn(L2I);
else if (dest.equals(TargetType.Float))
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)) {
mv.visitInsn(L2I);
convertTo(state, TargetType.Integer, dest);
}
} else if (source.equals(TargetType.Float)) {
if (dest.equals(TargetType.Integer))
mv.visitInsn(F2I);
else if (dest.equals(TargetType.Double))
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)) {
mv.visitInsn(F2I);
convertTo(state, TargetType.Integer, dest);
}
} else if (source.equals(TargetType.Double)) {
if (dest.equals(TargetType.Integer))
mv.visitInsn(D2I);
else if (dest.equals(TargetType.Float))
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)) {
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)) {
if (dest.equals(TargetType.Byte))
mv.visitInsn(I2B);
else if (dest.equals(TargetType.Char))
mv.visitInsn(I2C);
else if (dest.equals(TargetType.Short))
mv.visitInsn(I2S);
else if (dest.equals(TargetType.Long))
mv.visitInsn(I2L);
else if (dest.equals(TargetType.Float))
mv.visitInsn(I2F);
else if (dest.equals(TargetType.Double))
mv.visitInsn(I2D);
} else if (source.equals(TargetType.Boolean)) {
unboxPrimitive(state, dest);
} else if (isFunctionalInterface(source) && isFunctionalInterface(dest) &&
!(source instanceof TargetFunNType && dest instanceof TargetFunNType)) { !(source instanceof TargetFunNType && dest instanceof TargetFunNType)) {
boxFunctionalInterface(state, source, dest); boxFunctionalInterface(state, source, dest);
return; } else if (!(dest instanceof TargetGenericType)) {
} //boxPrimitive(state, source);
var mv = state.mv;
if ((source instanceof TargetRefType || source instanceof TargetGenericType) &&
(dest instanceof TargetRefType || dest instanceof TargetGenericType)) {
if (dest instanceof TargetGenericType) return;
mv.visitTypeInsn(CHECKCAST, dest.getInternalName()); mv.visitTypeInsn(CHECKCAST, dest.getInternalName());
return;
}
if (!(source instanceof TargetPrimitiveType)) {
unboxPrimitive(state, source);
source = TargetType.toPrimitive(source);
}
var origDest = dest;
dest = TargetType.toPrimitive(dest);
if (source.equals(TargetType.long_)) {
if (dest.equals(TargetType.int_))
mv.visitInsn(L2I);
else if (dest.equals(TargetType.float_))
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_)) {
mv.visitInsn(L2I);
convertTo(state, TargetType.int_, dest);
}
} else if (source.equals(TargetType.float_)) {
if (dest.equals(TargetType.int_))
mv.visitInsn(F2I);
else if (dest.equals(TargetType.double_))
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_)) {
mv.visitInsn(F2I);
convertTo(state, TargetType.int_, dest);
}
} else if (source.equals(TargetType.double_)) {
if (dest.equals(TargetType.int_))
mv.visitInsn(D2I);
else if (dest.equals(TargetType.float_))
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_)) {
mv.visitInsn(D2I);
convertTo(state, TargetType.int_, dest);
}
} else if (source.equals(TargetType.byte_) || source.equals(TargetType.char_) || source.equals(TargetType.short_) || source.equals(TargetType.int_)) {
if (dest.equals(TargetType.byte_))
mv.visitInsn(I2B);
else if (dest.equals(TargetType.char_))
mv.visitInsn(I2C);
else if (dest.equals(TargetType.short_))
mv.visitInsn(I2S);
else if (dest.equals(TargetType.long_))
mv.visitInsn(I2L);
else if (dest.equals(TargetType.float_))
mv.visitInsn(I2F);
else if (dest.equals(TargetType.double_))
mv.visitInsn(I2D);
} else if (source.equals(TargetType.boolean_)) {
unboxPrimitive(state, dest); unboxPrimitive(state, dest);
} }
if (!(origDest instanceof TargetPrimitiveType)) {
if (dest instanceof TargetPrimitiveType)
boxPrimitive(state, dest);
else boxPrimitive(state, source);
}
} }
record TypePair(TargetType from, TargetType to) {} record TypePair(TargetType from, TargetType to) {}
@@ -377,9 +350,9 @@ public class Codegen {
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/StringBuilder", "<init>", "(Ljava/lang/String;)V", false); mv.visitMethodInsn(INVOKESPECIAL, "java/lang/StringBuilder", "<init>", "(Ljava/lang/String;)V", false);
} else { } else {
generate(state, add.left()); generate(state, add.left());
convertTo(state, add.left().type(), TargetType.toPrimitive(add.type())); convertTo(state, add.left().type(), add.type());
generate(state, add.right()); generate(state, add.right());
convertTo(state, add.right().type(), TargetType.toPrimitive(add.type())); convertTo(state, add.right().type(), add.type());
var type = add.type(); var type = add.type();
if (type.equals(TargetType.Byte) || type.equals(TargetType.Char) || type.equals(TargetType.Integer) || type.equals(TargetType.Short)) { if (type.equals(TargetType.Byte) || type.equals(TargetType.Char) || type.equals(TargetType.Integer) || type.equals(TargetType.Short)) {
mv.visitInsn(IADD); mv.visitInsn(IADD);
@@ -392,7 +365,6 @@ public class Codegen {
} else { } else {
throw new CodeGenException("Invalid argument to Add expression, type: " + add.type()); throw new CodeGenException("Invalid argument to Add expression, type: " + add.type());
} }
boxPrimitive(state, TargetType.toPrimitive(op.type()));
} }
if (add.type().equals(TargetType.String)) { if (add.type().equals(TargetType.String)) {
generate(state, add.right()); generate(state, add.right());
@@ -404,9 +376,9 @@ public class Codegen {
} }
case Sub sub: { case Sub sub: {
generate(state, sub.left()); generate(state, sub.left());
convertTo(state, sub.left().type(), TargetType.toPrimitive(op.type())); convertTo(state, sub.left().type(), op.type());
generate(state, sub.right()); generate(state, sub.right());
convertTo(state, sub.right().type(), TargetType.toPrimitive(op.type())); convertTo(state, sub.right().type(), op.type());
var type = sub.type(); var type = sub.type();
if (type.equals(TargetType.Byte) || type.equals(TargetType.Char) || type.equals(TargetType.Integer) || type.equals(TargetType.Short)) { if (type.equals(TargetType.Byte) || type.equals(TargetType.Char) || type.equals(TargetType.Integer) || type.equals(TargetType.Short)) {
mv.visitInsn(ISUB); mv.visitInsn(ISUB);
@@ -419,14 +391,13 @@ public class Codegen {
} else { } else {
throw new CodeGenException("Invalid argument to Sub expression"); throw new CodeGenException("Invalid argument to Sub expression");
} }
boxPrimitive(state, TargetType.toPrimitive(op.type()));
break; break;
} }
case Div div: { case Div div: {
generate(state, div.left()); generate(state, div.left());
convertTo(state, div.left().type(), TargetType.toPrimitive(op.type())); convertTo(state, div.left().type(), op.type());
generate(state, div.right()); generate(state, div.right());
convertTo(state, div.right().type(), TargetType.toPrimitive(op.type())); convertTo(state, div.right().type(), op.type());
var type = div.type(); var type = div.type();
if (type.equals(TargetType.Byte) || type.equals(TargetType.Char) || type.equals(TargetType.Integer) || type.equals(TargetType.Short)) { if (type.equals(TargetType.Byte) || type.equals(TargetType.Char) || type.equals(TargetType.Integer) || type.equals(TargetType.Short)) {
mv.visitInsn(IDIV); mv.visitInsn(IDIV);
@@ -439,14 +410,13 @@ public class Codegen {
} else { } else {
throw new CodeGenException("Invalid argument to Div expression"); throw new CodeGenException("Invalid argument to Div expression");
} }
boxPrimitive(state, TargetType.toPrimitive(op.type()));
break; break;
} }
case Mul mul: { case Mul mul: {
generate(state, mul.left()); generate(state, mul.left());
convertTo(state, mul.left().type(), TargetType.toPrimitive(op.type())); convertTo(state, mul.left().type(), op.type());
generate(state, mul.right()); generate(state, mul.right());
convertTo(state, mul.right().type(), TargetType.toPrimitive(op.type())); convertTo(state, mul.right().type(), op.type());
var type = mul.type(); var type = mul.type();
if (type.equals(TargetType.Byte) || type.equals(TargetType.Char) || type.equals(TargetType.Integer) || type.equals(TargetType.Short)) { if (type.equals(TargetType.Byte) || type.equals(TargetType.Char) || type.equals(TargetType.Integer) || type.equals(TargetType.Short)) {
mv.visitInsn(IMUL); mv.visitInsn(IMUL);
@@ -459,14 +429,13 @@ public class Codegen {
} else { } else {
throw new CodeGenException("Invalid argument to Mul expression"); throw new CodeGenException("Invalid argument to Mul expression");
} }
boxPrimitive(state, TargetType.toPrimitive(op.type()));
break; break;
} }
case Rem rem: { case Rem rem: {
generate(state, rem.left()); generate(state, rem.left());
convertTo(state, rem.left().type(), TargetType.toPrimitive(op.type())); convertTo(state, rem.left().type(), op.type());
generate(state, rem.right()); generate(state, rem.right());
convertTo(state, rem.right().type(), TargetType.toPrimitive(op.type())); convertTo(state, rem.right().type(), op.type());
var type = rem.type(); var type = rem.type();
if (type.equals(TargetType.Byte) || type.equals(TargetType.Char) || type.equals(TargetType.Integer) || type.equals(TargetType.Short)) { if (type.equals(TargetType.Byte) || type.equals(TargetType.Char) || type.equals(TargetType.Integer) || type.equals(TargetType.Short)) {
mv.visitInsn(IREM); mv.visitInsn(IREM);
@@ -479,7 +448,6 @@ public class Codegen {
} else { } else {
throw new CodeGenException("Invalid argument to Rem expression"); throw new CodeGenException("Invalid argument to Rem expression");
} }
boxPrimitive(state, TargetType.toPrimitive(op.type()));
break; break;
} }
case Or or: { case Or or: {
@@ -487,18 +455,14 @@ public class Codegen {
Label or_true = new Label(); Label or_true = new Label();
Label end = new Label(); Label end = new Label();
generate(state, or.left()); generate(state, or.left());
convertTo(state, or.left().type(), TargetType.toPrimitive(op.type()));
mv.visitJumpInsn(IFNE, or_true); mv.visitJumpInsn(IFNE, or_true);
generate(state, or.right()); generate(state, or.right());
convertTo(state, or.right().type(), TargetType.toPrimitive(op.type()));
mv.visitJumpInsn(IFEQ, or_false); mv.visitJumpInsn(IFEQ, or_false);
mv.visitLabel(or_true); mv.visitLabel(or_true);
mv.visitInsn(ICONST_1); mv.visitInsn(ICONST_1);
boxPrimitive(state, TargetType.toPrimitive(op.type()));
mv.visitJumpInsn(GOTO, end); mv.visitJumpInsn(GOTO, end);
mv.visitLabel(or_false); mv.visitLabel(or_false);
mv.visitInsn(ICONST_0); mv.visitInsn(ICONST_0);
boxPrimitive(state, TargetType.toPrimitive(op.type()));
mv.visitLabel(end); mv.visitLabel(end);
break; break;
} }
@@ -506,54 +470,47 @@ public class Codegen {
Label and_false = new Label(); Label and_false = new Label();
Label end = new Label(); Label end = new Label();
generate(state, and.left()); generate(state, and.left());
convertTo(state, and.left().type(), TargetType.toPrimitive(op.type()));
mv.visitJumpInsn(IFEQ, and_false); mv.visitJumpInsn(IFEQ, and_false);
generate(state, and.right()); generate(state, and.right());
convertTo(state, and.right().type(), TargetType.toPrimitive(op.type()));
mv.visitJumpInsn(IFEQ, and_false); mv.visitJumpInsn(IFEQ, and_false);
mv.visitInsn(ICONST_1); mv.visitInsn(ICONST_1);
boxPrimitive(state, TargetType.toPrimitive(op.type()));
mv.visitJumpInsn(GOTO, end); mv.visitJumpInsn(GOTO, end);
mv.visitLabel(and_false); mv.visitLabel(and_false);
mv.visitInsn(ICONST_0); mv.visitInsn(ICONST_0);
boxPrimitive(state, TargetType.toPrimitive(op.type()));
mv.visitLabel(end); mv.visitLabel(end);
break; break;
} }
case BAnd band: { case BAnd band: {
generate(state, band.left()); generate(state, band.left());
convertTo(state, band.left().type(), TargetType.toPrimitive(op.type())); convertTo(state, band.left().type(), op.type());
generate(state, band.right()); generate(state, band.right());
convertTo(state, band.right().type(), TargetType.toPrimitive(op.type())); convertTo(state, band.right().type(), op.type());
if (band.type().equals(TargetType.Long)) if (band.type().equals(TargetType.Long))
mv.visitInsn(LAND); mv.visitInsn(LAND);
else else
mv.visitInsn(IAND); mv.visitInsn(IAND);
boxPrimitive(state, TargetType.toPrimitive(op.type()));
break; break;
} }
case BOr bor: { case BOr bor: {
generate(state, bor.left()); generate(state, bor.left());
convertTo(state, bor.left().type(), TargetType.toPrimitive(op.type())); convertTo(state, bor.left().type(), op.type());
generate(state, bor.right()); generate(state, bor.right());
convertTo(state, bor.right().type(), TargetType.toPrimitive(op.type())); convertTo(state, bor.right().type(), op.type());
if (bor.type().equals(TargetType.Long)) if (bor.type().equals(TargetType.Long))
mv.visitInsn(LOR); mv.visitInsn(LOR);
else else
mv.visitInsn(IOR); mv.visitInsn(IOR);
boxPrimitive(state, TargetType.toPrimitive(op.type()));
break; break;
} }
case XOr xor: { case XOr xor: {
generate(state, xor.left()); generate(state, xor.left());
convertTo(state, xor.left().type(), TargetType.toPrimitive(op.type())); convertTo(state, xor.left().type(), op.type());
generate(state, xor.right()); generate(state, xor.right());
convertTo(state, xor.right().type(), TargetType.toPrimitive(op.type())); convertTo(state, xor.right().type(), op.type());
if (xor.type().equals(TargetType.Long)) if (xor.type().equals(TargetType.Long))
mv.visitInsn(LXOR); mv.visitInsn(LXOR);
else else
mv.visitInsn(IXOR); mv.visitInsn(IXOR);
boxPrimitive(state, TargetType.toPrimitive(op.type()));
break; break;
} }
case Instof instof: { case Instof instof: {
@@ -562,47 +519,44 @@ public class Codegen {
} }
case Shl shl: { case Shl shl: {
generate(state, shl.left()); generate(state, shl.left());
convertTo(state, shl.left().type(), TargetType.toPrimitive(op.type())); convertTo(state, shl.left().type(), op.type());
generate(state, shl.right()); generate(state, shl.right());
convertTo(state, shl.right().type(), TargetType.toPrimitive(op.type())); convertTo(state, shl.right().type(), op.type());
if (shl.type().equals(TargetType.Long)) if (shl.type().equals(TargetType.Long))
mv.visitInsn(LSHL); mv.visitInsn(LSHL);
else else
mv.visitInsn(ISHL); mv.visitInsn(ISHL);
boxPrimitive(state, TargetType.toPrimitive(op.type()));
break; break;
} }
case Shr shr: { case Shr shr: {
generate(state, shr.left()); generate(state, shr.left());
convertTo(state, shr.left().type(), TargetType.toPrimitive(op.type())); convertTo(state, shr.left().type(), op.type());
generate(state, shr.right()); generate(state, shr.right());
convertTo(state, shr.right().type(), TargetType.toPrimitive(op.type())); convertTo(state, shr.right().type(), op.type());
if (shr.type().equals(TargetType.Long)) if (shr.type().equals(TargetType.Long))
mv.visitInsn(LSHR); mv.visitInsn(LSHR);
else else
mv.visitInsn(ISHR); mv.visitInsn(ISHR);
boxPrimitive(state, TargetType.toPrimitive(op.type()));
break; break;
} }
case UShr ushr: { case UShr ushr: {
generate(state, ushr.left()); generate(state, ushr.left());
convertTo(state, ushr.left().type(), TargetType.toPrimitive(op.type())); convertTo(state, ushr.left().type(), op.type());
generate(state, ushr.right()); generate(state, ushr.right());
convertTo(state, ushr.right().type(), TargetType.toPrimitive(op.type())); convertTo(state, ushr.right().type(), op.type());
if (ushr.type().equals(TargetType.Long)) if (ushr.type().equals(TargetType.Long))
mv.visitInsn(LUSHR); mv.visitInsn(LUSHR);
else else
mv.visitInsn(IUSHR); mv.visitInsn(IUSHR);
boxPrimitive(state, TargetType.toPrimitive(op.type()));
break; break;
} }
case Greater greater: { case Greater greater: {
var type = TargetType.toPrimitive(largerType(greater.left().type(), greater.right().type())); var type = largerType(greater.left().type(), greater.right().type());
if (type.equals(TargetType.long_)) { if (type.equals(TargetType.Long)) {
generateRelationalOperator(state, greater, type, LCMP, IFGT); generateRelationalOperator(state, greater, type, LCMP, IFGT);
} else if (type.equals(TargetType.float_)) { } else if (type.equals(TargetType.Float)) {
generateRelationalOperator(state, greater, type, FCMPL, IFGT); generateRelationalOperator(state, greater, type, FCMPL, IFGT);
} else if (type.equals(TargetType.double_)) { } else if (type.equals(TargetType.Double)) {
generateRelationalOperator(state, greater, type, DCMPL, IFGT); generateRelationalOperator(state, greater, type, DCMPL, IFGT);
} else { } else {
generateRelationalOperator(state, greater, type, IF_ICMPGT); generateRelationalOperator(state, greater, type, IF_ICMPGT);
@@ -610,12 +564,12 @@ public class Codegen {
break; break;
} }
case Less less: { case Less less: {
var type = TargetType.toPrimitive(largerType(less.left().type(), less.right().type())); var type = largerType(less.left().type(), less.right().type());
if (type.equals(TargetType.long_)) { if (type.equals(TargetType.Long)) {
generateRelationalOperator(state, less, type, LCMP, IFLT); generateRelationalOperator(state, less, type, LCMP, IFLT);
} else if (type.equals(TargetType.float_)) { } else if (type.equals(TargetType.Float)) {
generateRelationalOperator(state, less, type, FCMPL, IFLT); generateRelationalOperator(state, less, type, FCMPL, IFLT);
} else if (type.equals(TargetType.double_)) { } else if (type.equals(TargetType.Double)) {
generateRelationalOperator(state, less, type, DCMPL, IFLT); generateRelationalOperator(state, less, type, DCMPL, IFLT);
} else { } else {
generateRelationalOperator(state, less, type, IF_ICMPLT); generateRelationalOperator(state, less, type, IF_ICMPLT);
@@ -623,12 +577,12 @@ public class Codegen {
break; break;
} }
case GreaterOrEqual greaterOrEqual: { case GreaterOrEqual greaterOrEqual: {
var type = TargetType.toPrimitive(largerType(greaterOrEqual.left().type(), greaterOrEqual.right().type())); var type = largerType(greaterOrEqual.left().type(), greaterOrEqual.right().type());
if (type.equals(TargetType.long_)) { if (type.equals(TargetType.Long)) {
generateRelationalOperator(state, greaterOrEqual, type, LCMP, IFGE); generateRelationalOperator(state, greaterOrEqual, type, LCMP, IFGE);
} else if (type.equals(TargetType.float_)) { } else if (type.equals(TargetType.Float)) {
generateRelationalOperator(state, greaterOrEqual, type, FCMPL, IFGE); generateRelationalOperator(state, greaterOrEqual, type, FCMPL, IFGE);
} else if (type.equals(TargetType.double_)) { } else if (type.equals(TargetType.Double)) {
generateRelationalOperator(state, greaterOrEqual, type, DCMPL, IFGE); generateRelationalOperator(state, greaterOrEqual, type, DCMPL, IFGE);
} else { } else {
generateRelationalOperator(state, greaterOrEqual, type, IF_ICMPGE); generateRelationalOperator(state, greaterOrEqual, type, IF_ICMPGE);
@@ -636,12 +590,12 @@ public class Codegen {
break; break;
} }
case LessOrEqual lessOrEqual: { case LessOrEqual lessOrEqual: {
var type = TargetType.toPrimitive(largerType(lessOrEqual.left().type(), lessOrEqual.right().type())); var type = largerType(lessOrEqual.left().type(), lessOrEqual.right().type());
if (type.equals(TargetType.long_)) { if (type.equals(TargetType.Long)) {
generateRelationalOperator(state, lessOrEqual, type, LCMP, IFLE); generateRelationalOperator(state, lessOrEqual, type, LCMP, IFLE);
} else if (type.equals(TargetType.float_)) { } else if (type.equals(TargetType.Float)) {
generateRelationalOperator(state, lessOrEqual, type, FCMPL, IFLE); generateRelationalOperator(state, lessOrEqual, type, FCMPL, IFLE);
} else if (type.equals(TargetType.double_)) { } else if (type.equals(TargetType.Double)) {
generateRelationalOperator(state, lessOrEqual, type, DCMPL, IFLE); generateRelationalOperator(state, lessOrEqual, type, DCMPL, IFLE);
} else { } else {
generateRelationalOperator(state, lessOrEqual, type, IF_ICMPLE); generateRelationalOperator(state, lessOrEqual, type, IF_ICMPLE);
@@ -649,30 +603,30 @@ public class Codegen {
break; break;
} }
case Equal equal: { case Equal equal: {
var type = TargetType.toPrimitive(largerType(equal.left().type(), equal.right().type())); var type = largerType(equal.left().type(), equal.right().type());
if (type.equals(TargetType.long_)) { if (type.equals(TargetType.Long)) {
generateRelationalOperator(state, equal, TargetType.long_, LCMP, IFEQ); generateRelationalOperator(state, equal, type, LCMP, IFEQ);
} else if (type.equals(TargetType.float_)) { } else if (type.equals(TargetType.Float)) {
generateRelationalOperator(state, equal, TargetType.float_, FCMPL, IFEQ); generateRelationalOperator(state, equal, type, FCMPL, IFEQ);
} else if (type.equals(TargetType.double_)) { } else if (type.equals(TargetType.Double)) {
generateRelationalOperator(state, equal, TargetType.double_, DCMPL, IFEQ); generateRelationalOperator(state, equal, type, DCMPL, IFEQ);
} else if (type.equals(TargetType.char_) || type.equals(TargetType.short_) || type.equals(TargetType.byte_) || type.equals(TargetType.int_) || type.equals(TargetType.boolean_)) { } 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, TargetType.int_, IF_ICMPEQ); generateRelationalOperator(state, equal, type, IF_ICMPEQ);
} else { } else {
generateRelationalOperator(state, equal, type, IF_ACMPEQ); generateRelationalOperator(state, equal, type, IF_ACMPEQ);
} }
break; break;
} }
case NotEqual notEqual: { case NotEqual notEqual: {
var type = TargetType.toPrimitive(largerType(notEqual.left().type(), notEqual.right().type())); var type = largerType(notEqual.left().type(), notEqual.right().type());
if (type.equals(TargetType.long_)) { if (type.equals(TargetType.Long)) {
generateRelationalOperator(state, notEqual, TargetType.long_, LCMP, IFNE); generateRelationalOperator(state, notEqual, type, LCMP, IFNE);
} else if (type.equals(TargetType.float_)) { } else if (type.equals(TargetType.Float)) {
generateRelationalOperator(state, notEqual, TargetType.float_, FCMPL, IFNE); generateRelationalOperator(state, notEqual, type, FCMPL, IFNE);
} else if (type.equals(TargetType.double_)) { } else if (type.equals(TargetType.Double)) {
generateRelationalOperator(state, notEqual, TargetType.double_, DCMPL, IFNE); generateRelationalOperator(state, notEqual, type, DCMPL, IFNE);
} else if (type.equals(TargetType.char_) || type.equals(TargetType.short_) || type.equals(TargetType.byte_) || type.equals(TargetType.int_) || type.equals(TargetType.boolean_)) { } else if (type.equals(TargetType.Char) || type.equals(TargetType.Short) || type.equals(TargetType.Byte) || type.equals(TargetType.Integer)) {
generateRelationalOperator(state, notEqual, TargetType.int_, IF_ICMPNE); generateRelationalOperator(state, notEqual, type, IF_ICMPNE);
} else { } else {
generateRelationalOperator(state, notEqual, type, IF_ACMPNE); generateRelationalOperator(state, notEqual, type, IF_ACMPNE);
} }
@@ -703,7 +657,6 @@ public class Codegen {
generate(state, add.expr()); generate(state, add.expr());
case TargetUnaryOp.Negate negate -> { case TargetUnaryOp.Negate negate -> {
generate(state, negate.expr()); generate(state, negate.expr());
convertTo(state, negate.expr().type(), TargetType.boolean_);
if (negate.type().equals(TargetType.Double)) if (negate.type().equals(TargetType.Double))
mv.visitInsn(DNEG); mv.visitInsn(DNEG);
else if (negate.type().equals(TargetType.Float)) else if (negate.type().equals(TargetType.Float))
@@ -712,11 +665,9 @@ public class Codegen {
mv.visitInsn(LNEG); mv.visitInsn(LNEG);
else else
mv.visitInsn(INEG); mv.visitInsn(INEG);
boxPrimitive(state, TargetType.toPrimitive(negate.expr().type()));
} }
case TargetUnaryOp.Not not -> { case TargetUnaryOp.Not not -> {
generate(state, not.expr()); generate(state, not.expr());
convertTo(state, not.expr().type(), TargetType.boolean_);
if (not.type().equals(TargetType.Long)) { if (not.type().equals(TargetType.Long)) {
mv.visitLdcInsn(-1L); mv.visitLdcInsn(-1L);
mv.visitInsn(LXOR); mv.visitInsn(LXOR);
@@ -724,86 +675,93 @@ public class Codegen {
mv.visitInsn(ICONST_M1); mv.visitInsn(ICONST_M1);
mv.visitInsn(IXOR); mv.visitInsn(IXOR);
} }
boxPrimitive(state, TargetType.toPrimitive(not.expr().type()));
} }
case TargetUnaryOp.PreIncrement preIncrement -> { case TargetUnaryOp.PreIncrement preIncrement -> {
generate(state, preIncrement.expr()); generate(state, preIncrement.expr());
convertTo(state, preIncrement.expr().type(), TargetType.toPrimitive(op.type()));
if (preIncrement.type().equals(TargetType.Float)) { if (preIncrement.type().equals(TargetType.Float)) {
mv.visitLdcInsn(1F); mv.visitLdcInsn(1F);
mv.visitInsn(FADD); mv.visitInsn(FADD);
mv.visitInsn(DUP);
} else if (preIncrement.type().equals(TargetType.Double)) { } else if (preIncrement.type().equals(TargetType.Double)) {
mv.visitLdcInsn(1D); mv.visitLdcInsn(1D);
mv.visitInsn(DADD); mv.visitInsn(DADD);
mv.visitInsn(DUP2);
} else if (preIncrement.type().equals(TargetType.Long)) { } else if (preIncrement.type().equals(TargetType.Long)) {
mv.visitLdcInsn(1L); mv.visitLdcInsn(1L);
mv.visitInsn(LADD); mv.visitInsn(LADD);
mv.visitInsn(DUP2);
} else { } else {
mv.visitLdcInsn(1); mv.visitLdcInsn(1);
mv.visitInsn(IADD); mv.visitInsn(IADD);
mv.visitInsn(DUP);
} }
boxPrimitive(state, TargetType.toPrimitive(op.type())); boxPrimitive(state, preIncrement.type());
mv.visitInsn(DUP);
afterIncDec(state, preIncrement); afterIncDec(state, preIncrement);
} }
case TargetUnaryOp.PreDecrement preDecrement -> { case TargetUnaryOp.PreDecrement preDecrement -> {
generate(state, preDecrement.expr()); generate(state, preDecrement.expr());
convertTo(state, preDecrement.expr().type(), TargetType.toPrimitive(op.type()));
if (preDecrement.type().equals(TargetType.Float)) { if (preDecrement.type().equals(TargetType.Float)) {
mv.visitLdcInsn(1F); mv.visitLdcInsn(1F);
mv.visitInsn(FSUB); mv.visitInsn(FSUB);
mv.visitInsn(DUP);
} else if (preDecrement.type().equals(TargetType.Double)) { } else if (preDecrement.type().equals(TargetType.Double)) {
mv.visitLdcInsn(1D); mv.visitLdcInsn(1D);
mv.visitInsn(DSUB); mv.visitInsn(DSUB);
mv.visitInsn(DUP2);
} else if (preDecrement.type().equals(TargetType.Long)) { } else if (preDecrement.type().equals(TargetType.Long)) {
mv.visitLdcInsn(1L); mv.visitLdcInsn(1L);
mv.visitInsn(LSUB); mv.visitInsn(LSUB);
mv.visitInsn(DUP2);
} else { } else {
mv.visitLdcInsn(1); mv.visitLdcInsn(1);
mv.visitInsn(ISUB); mv.visitInsn(ISUB);
mv.visitInsn(DUP);
} }
boxPrimitive(state, TargetType.toPrimitive(op.type())); boxPrimitive(state, preDecrement.type());
mv.visitInsn(DUP);
afterIncDec(state, preDecrement); afterIncDec(state, preDecrement);
} }
case TargetUnaryOp.PostIncrement postIncrement -> { case TargetUnaryOp.PostIncrement postIncrement -> {
generate(state, postIncrement.expr()); generate(state, postIncrement.expr());
mv.visitInsn(DUP);
convertTo(state, postIncrement.expr().type(), TargetType.toPrimitive(op.type()));
if (postIncrement.type().equals(TargetType.Float)) { if (postIncrement.type().equals(TargetType.Float)) {
mv.visitInsn(DUP);
mv.visitLdcInsn(1F); mv.visitLdcInsn(1F);
mv.visitInsn(FADD); mv.visitInsn(FADD);
} else if (postIncrement.type().equals(TargetType.Double)) { } else if (postIncrement.type().equals(TargetType.Double)) {
mv.visitInsn(DUP2);
mv.visitLdcInsn(1D); mv.visitLdcInsn(1D);
mv.visitInsn(DADD); mv.visitInsn(DADD);
} else if (postIncrement.type().equals(TargetType.Long)) { } else if (postIncrement.type().equals(TargetType.Long)) {
mv.visitInsn(DUP2);
mv.visitLdcInsn(1L); mv.visitLdcInsn(1L);
mv.visitInsn(LADD); mv.visitInsn(LADD);
} else { } else {
mv.visitInsn(DUP);
mv.visitLdcInsn(1); mv.visitLdcInsn(1);
mv.visitInsn(IADD); mv.visitInsn(IADD);
} }
boxPrimitive(state, TargetType.toPrimitive(op.type())); boxPrimitive(state, postIncrement.type());
afterIncDec(state, postIncrement); afterIncDec(state, postIncrement);
} }
case TargetUnaryOp.PostDecrement postDecrement -> { case TargetUnaryOp.PostDecrement postDecrement -> {
generate(state, postDecrement.expr()); generate(state, postDecrement.expr());
mv.visitInsn(DUP);
convertTo(state, postDecrement.expr().type(), TargetType.toPrimitive(op.type()));
if (postDecrement.type().equals(TargetType.Float)) { if (postDecrement.type().equals(TargetType.Float)) {
mv.visitInsn(DUP);
mv.visitLdcInsn(1F); mv.visitLdcInsn(1F);
mv.visitInsn(FSUB); mv.visitInsn(FSUB);
} else if (postDecrement.type().equals(TargetType.Double)) { } else if (postDecrement.type().equals(TargetType.Double)) {
mv.visitInsn(DUP2);
mv.visitLdcInsn(1D); mv.visitLdcInsn(1D);
mv.visitInsn(DSUB); mv.visitInsn(DSUB);
} else if (postDecrement.type().equals(TargetType.Long)) { } else if (postDecrement.type().equals(TargetType.Long)) {
mv.visitInsn(DUP2);
mv.visitLdcInsn(1L); mv.visitLdcInsn(1L);
mv.visitInsn(LSUB); mv.visitInsn(LSUB);
} else { } else {
mv.visitInsn(DUP);
mv.visitLdcInsn(1); mv.visitLdcInsn(1);
mv.visitInsn(ISUB); mv.visitInsn(ISUB);
} }
boxPrimitive(state, TargetType.toPrimitive(op.type())); boxPrimitive(state, postDecrement.type());
afterIncDec(state, postDecrement); afterIncDec(state, postDecrement);
} }
} }
@@ -951,7 +909,7 @@ public class Codegen {
var local = state.createVariable(varDecl.name(), varDecl.varType()); var local = state.createVariable(varDecl.name(), varDecl.varType());
if (varDecl.value() != null) { if (varDecl.value() != null) {
generate(state, varDecl.value()); generate(state, varDecl.value());
boxPrimitive(state, varDecl.value().type()); boxPrimitive(state, varDecl.varType());
mv.visitVarInsn(ASTORE, local.index()); mv.visitVarInsn(ASTORE, local.index());
} else { } else {
mv.visitInsn(ACONST_NULL); mv.visitInsn(ACONST_NULL);
@@ -1000,14 +958,14 @@ public class Codegen {
mv.visitVarInsn(ALOAD, local.index()); mv.visitVarInsn(ALOAD, local.index());
// This is a bit weird but sometimes the types don't match (see lambda expressions) // This is a bit weird but sometimes the types don't match (see lambda expressions)
convertTo(state, local.type(), localVar.type()); convertTo(state, local.type(), localVar.type());
//unboxPrimitive(state, local.type()); unboxPrimitive(state, local.type());
break; break;
} }
case TargetFieldVar dot: { case TargetFieldVar dot: {
if (!dot.isStatic()) if (!dot.isStatic())
generate(state, dot.left()); generate(state, dot.left());
mv.visitFieldInsn(dot.isStatic() ? GETSTATIC : GETFIELD, dot.left().type().getInternalName(), dot.right(), dot.type().toDescriptor()); mv.visitFieldInsn(dot.isStatic() ? GETSTATIC : GETFIELD, dot.left().type().getInternalName(), dot.right(), dot.type().toDescriptor());
//unboxPrimitive(state, dot.type()); unboxPrimitive(state, dot.type());
break; break;
} }
case TargetFor _for: { case TargetFor _for: {
@@ -1023,14 +981,11 @@ public class Codegen {
Label start = new Label(); Label start = new Label();
Label end = new Label(); Label end = new Label();
mv.visitLabel(start); mv.visitLabel(start);
if (_for.termination() != null) { if (_for.termination() != null)
generate(state, _for.termination()); generate(state, _for.termination());
convertTo(state, _for.termination().type(), TargetType.boolean_); else
mv.visitJumpInsn(IFEQ, end);
} else {
mv.visitInsn(ICONST_1); mv.visitInsn(ICONST_1);
mv.visitJumpInsn(IFEQ, end); mv.visitJumpInsn(IFEQ, end);
}
var env = new BreakEnv(); var env = new BreakEnv();
env.startLabel = start; env.startLabel = start;
@@ -1062,7 +1017,6 @@ public class Codegen {
Label end = new Label(); Label end = new Label();
mv.visitLabel(start); mv.visitLabel(start);
generate(state, _while.cond()); generate(state, _while.cond());
convertTo(state, _while.cond().type(), TargetType.boolean_);
mv.visitJumpInsn(IFEQ, end); mv.visitJumpInsn(IFEQ, end);
var env = new BreakEnv(); var env = new BreakEnv();
@@ -1093,7 +1047,6 @@ public class Codegen {
mv.visitLabel(check); mv.visitLabel(check);
generate(state, _do.cond()); generate(state, _do.cond());
convertTo(state, _do.cond().type(), TargetType.boolean_);
mv.visitJumpInsn(IFEQ, end); mv.visitJumpInsn(IFEQ, end);
mv.visitJumpInsn(GOTO, start); mv.visitJumpInsn(GOTO, start);
mv.visitLabel(end); mv.visitLabel(end);
@@ -1101,7 +1054,6 @@ public class Codegen {
} }
case TargetIf _if: { case TargetIf _if: {
generate(state, _if.cond()); generate(state, _if.cond());
convertTo(state, _if.cond().type(), TargetType.boolean_);
Label _else = new Label(); Label _else = new Label();
Label end = new Label(); Label end = new Label();
mv.visitJumpInsn(IFEQ, _else); mv.visitJumpInsn(IFEQ, _else);
@@ -1115,23 +1067,20 @@ public class Codegen {
break; break;
} }
case TargetReturn ret: { case TargetReturn ret: {
if (ret.expression() != null) { if (ret.expression() != null && state.returnType != null) {
if (state.returnType instanceof TargetPrimitiveType) { if (state.returnType instanceof TargetPrimitiveType) {
generate(state, ret.expression()); generate(state, ret.expression());
// Lambdas wrap the expression in a return if they are a single expression
// It means we have to execute the code anyway but not return anything unboxPrimitive(state, state.returnType);
if (state.returnType != null) { mv.visitInsn(findReturnCode(state.returnType));
convertTo(state, ret.expression().type(), state.returnType);
mv.visitInsn(findReturnCode(state.returnType));
}
} else { } else {
generate(state, ret.expression()); generate(state, ret.expression());
if (state.returnType != null) { boxPrimitive(state, ret.expression().type());
convertTo(state, ret.expression().type(), state.returnType); convertTo(state, ret.expression().type(), state.returnType);
mv.visitInsn(ARETURN); mv.visitInsn(ARETURN);
}
} }
} else mv.visitInsn(RETURN); } else
mv.visitInsn(RETURN);
break; break;
} }
case TargetYield yield: { case TargetYield yield: {
@@ -1178,14 +1127,12 @@ public class Codegen {
var arg = call.parameterTypes().get(i); var arg = call.parameterTypes().get(i);
generate(state, e); generate(state, e);
convertTo(state, e.type(), arg); convertTo(state, e.type(), arg);
if (!(arg instanceof TargetPrimitiveType))
boxPrimitive(state, e.type());
} }
var descriptor = call.getDescriptor(); var descriptor = call.getDescriptor();
if (call.owner() instanceof TargetFunNType owner) { if (call.owner() instanceof TargetFunNType) // Decay FunN
// Decay FunN descriptor = TargetMethod.getDescriptor(call.returnType() == null ? null : TargetType.Object, call.parameterTypes().stream().map(x -> TargetType.Object).toArray(TargetType[]::new));
descriptor = TargetMethod.getDescriptor(
(owner.returnArguments() == 0 ? null : TargetType.Object),
call.parameterTypes().stream().map(x -> TargetType.Object).toArray(TargetType[]::new));
}
int insn = INVOKEVIRTUAL; int insn = INVOKEVIRTUAL;
if (call.isStatic()) insn = INVOKESTATIC; if (call.isStatic()) insn = INVOKESTATIC;
@@ -1194,13 +1141,11 @@ public class Codegen {
mv.visitMethodInsn(insn, call.owner().getInternalName(), call.name(), descriptor, call.isInterface()); mv.visitMethodInsn(insn, call.owner().getInternalName(), call.name(), descriptor, call.isInterface());
/*if (call.type() != null && call.returnType() != null && !(call.returnType() instanceof TargetPrimitiveType)) { if (call.type() != null && call.returnType() != null && !(call.returnType() instanceof TargetPrimitiveType)) {
if (!call.returnType().equals(call.type()) && !(call.type() instanceof TargetGenericType)) if (!call.returnType().equals(call.type()) && !(call.type() instanceof TargetGenericType))
mv.visitTypeInsn(CHECKCAST, call.type().getInternalName()); mv.visitTypeInsn(CHECKCAST, call.type().getInternalName());
unboxPrimitive(state, call.type()); unboxPrimitive(state, call.type());
}*/ }
if (call.type() != null)
convertTo(state, call.returnType(), call.type());
break; break;
} }
case TargetLambdaExpression lambda: case TargetLambdaExpression lambda:
@@ -1209,10 +1154,9 @@ public class Codegen {
case TargetNew _new: { case TargetNew _new: {
mv.visitTypeInsn(NEW, _new.type().getInternalName()); mv.visitTypeInsn(NEW, _new.type().getInternalName());
mv.visitInsn(DUP); mv.visitInsn(DUP);
for (var i = 0; i < _new.params().size(); i++) { for (TargetExpression e : _new.params()) {
var e = _new.params().get(i);
generate(state, e); generate(state, e);
convertTo(state, e.type(), _new.signature().get(i)); boxPrimitive(state, e.type());
} }
mv.visitMethodInsn(INVOKESPECIAL, _new.type().getInternalName(), "<init>", _new.getDescriptor(), false); mv.visitMethodInsn(INVOKESPECIAL, _new.type().getInternalName(), "<init>", _new.getDescriptor(), false);
break; break;
@@ -1224,7 +1168,6 @@ public class Codegen {
} }
case TargetTernary ternary: { case TargetTernary ternary: {
generate(state, ternary.cond()); generate(state, ternary.cond());
convertTo(state, ternary.cond().type(), TargetType.boolean_);
var iffalse = new Label(); var iffalse = new Label();
var end = new Label(); var end = new Label();
mv.visitJumpInsn(IFEQ, iffalse); mv.visitJumpInsn(IFEQ, iffalse);
@@ -1278,7 +1221,6 @@ public class Codegen {
if (instanceOf.right() instanceof TargetTypePattern right && right.name() == null) { if (instanceOf.right() instanceof TargetTypePattern right && right.name() == null) {
generate(state, instanceOf.left()); generate(state, instanceOf.left());
mv.visitTypeInsn(INSTANCEOF, right.type().getInternalName()); mv.visitTypeInsn(INSTANCEOF, right.type().getInternalName());
boxPrimitive(state, TargetType.boolean_);
return; return;
} }
@@ -1286,7 +1228,6 @@ public class Codegen {
} }
private void yieldValue(State state, TargetType type) { private void yieldValue(State state, TargetType type) {
if (type == null) return;
boxPrimitive(state, type); boxPrimitive(state, type);
state.mv.visitVarInsn(ASTORE, state.switchResultValue.peek()); state.mv.visitVarInsn(ASTORE, state.switchResultValue.peek());
} }
@@ -1302,7 +1243,6 @@ public class Codegen {
state.pushSwitch(); state.pushSwitch();
generate(state, aSwitch.expr()); generate(state, aSwitch.expr());
unboxPrimitive(state, aSwitch.expr().type());
state.enterScope(); state.enterScope();
@@ -1438,7 +1378,6 @@ public class Codegen {
if (label instanceof TargetGuard gd) { if (label instanceof TargetGuard gd) {
generate(state, gd.expression()); generate(state, gd.expression());
unboxPrimitive(state, TargetType.Boolean);
var next = new Label(); var next = new Label();
mv.visitJumpInsn(IFNE, next); mv.visitJumpInsn(IFNE, next);
mv.visitVarInsn(ALOAD, tmp); mv.visitVarInsn(ALOAD, tmp);
@@ -1476,7 +1415,7 @@ public class Codegen {
if (aSwitch.isExpression()) { if (aSwitch.isExpression()) {
if (aSwitch.type() != null) { if (aSwitch.type() != null) {
mv.visitVarInsn(ALOAD, state.switchResultValue.peek()); mv.visitVarInsn(ALOAD, state.switchResultValue.peek());
//unboxPrimitive(state, aSwitch.type()); unboxPrimitive(state, aSwitch.type());
} }
state.popSwitch(); state.popSwitch();
} }
@@ -1493,8 +1432,8 @@ public class Codegen {
} }
private void bindPattern(State state, TargetType type, TargetPattern pat, Label start, int index, int depth) { private void bindPattern(State state, TargetType type, TargetPattern pat, Label start, int index, int depth) {
//if (pat.type() instanceof TargetPrimitiveType) if (pat.type() instanceof TargetPrimitiveType)
// boxPrimitive(state, pat.type()); boxPrimitive(state, pat.type());
if (pat.type() instanceof TargetRefType) { if (pat.type() instanceof TargetRefType) {
state.mv.visitInsn(DUP); state.mv.visitInsn(DUP);
@@ -1515,14 +1454,11 @@ public class Codegen {
} }
if (pat instanceof TargetExpressionPattern ep) { if (pat instanceof TargetExpressionPattern ep) {
var cur = state.createVariable(TargetType.toWrapper(pat.type())); var cur = state.createVariable(pat.type());
state.mv.visitVarInsn(ASTORE, cur.index); state.mv.visitVarInsn(ASTORE, cur.index);
// For Strings we must use equals, and why not make it work for all types? var expr = new Equal(pat.type(), new TargetLocalVar(cur.type, cur.name), ep.expression());
generate(state, new TargetLocalVar(cur.type, cur.name)); generate(state, expr);
generate(state, ep.expression());
boxPrimitive(state, ep.expression().type());
state.mv.visitMethodInsn(INVOKESTATIC, "java/util/Objects", "equals", "(Ljava/lang/Object;Ljava/lang/Object;)Z", false);
var cont = new Label(); var cont = new Label();
state.mv.visitJumpInsn(IFNE, cont); state.mv.visitJumpInsn(IFNE, cont);
@@ -1720,7 +1656,7 @@ public class Codegen {
generate(state, method.block()); generate(state, method.block());
if (method.signature().returnType() == null) if (method.signature().returnType() == null)
mv.visitInsn(RETURN); mv.visitInsn(RETURN);
mv.visitMaxs(0, 0); mv.visitMaxs(0, 0);
} }
mv.visitEnd(); mv.visitEnd();
} }
@@ -1736,8 +1672,6 @@ public class Codegen {
} }
if (clazz.superType() != null) if (clazz.superType() != null)
ret += clazz.superType().toSignature(); ret += clazz.superType().toSignature();
else ret += "Ljava/lang/Object;";
for (var intf : clazz.implementingInterfaces()) { for (var intf : clazz.implementingInterfaces()) {
ret += intf.toSignature(); ret += intf.toSignature();
} }
@@ -1840,12 +1774,8 @@ public class Codegen {
} else convertTo(state, fromReturn, toReturn); } else convertTo(state, fromReturn, toReturn);
} }
if (toReturn != null) { if (toReturn != null)
if ((fromReturn instanceof TargetRefType || fromReturn instanceof TargetGenericType)
&& (toReturn instanceof TargetPrimitiveType))
unboxPrimitive(state, TargetType.toWrapper(toReturn));
mv.visitInsn(findReturnCode(toReturn)); mv.visitInsn(findReturnCode(toReturn));
}
else mv.visitInsn(RETURN); else mv.visitInsn(RETURN);
mv.visitMaxs(0, 0); mv.visitMaxs(0, 0);
@@ -1854,13 +1784,19 @@ public class Codegen {
cw2.visitEnd(); cw2.visitEnd();
var bytes = cw2.toByteArray(); var bytes = cw2.toByteArray();
compiler.auxiliaries.put(className, bytes); compiler.auxiliaries.put(className, bytes);
// TODO These class loading shenanigans happen in a few places, the tests load the classes individually.
// Instead we should just look at the folder.
try {
converter.classLoader.findClass(className);
} catch (ClassNotFoundException e) {
try {
converter.classLoader.loadClass(className, bytes);
} catch (LinkageError ignored) {}
}
} }
cw.visitEnd(); cw.visitEnd();
//ClassReader cr = new ClassReader(cw.toByteArray());
//System.out.println("Checking class " + className);
// TODO This fails for multi class projects because it tries to load the other classes
//CheckClassAdapter.verify(cr, false, new PrintWriter(System.err));
return cw.toByteArray(); return cw.toByteArray();
} }

View File

@@ -75,7 +75,7 @@ public class FunNGenerator {
if (type == null) return VOID; if (type == null) return VOID;
var res = "L" + type.getInternalName(); var res = "L" + type.getInternalName();
if (type instanceof TargetSpecializedType a) { if (type instanceof TargetSpecializedType a) {
if (!a.params().isEmpty() && !(a.params().size() == 1 && a.params().getFirst() == null)) { if (a.params().size() > 0) {
res += "<"; res += "<";
for (var param : a.params()) { for (var param : a.params()) {
if (param instanceof TargetGenericType gp) { if (param instanceof TargetGenericType gp) {
@@ -115,12 +115,11 @@ public class FunNGenerator {
superFunNMethodSignature.append(String.format("T%s;", argumentGenericBase + currentParameter)); superFunNMethodSignature.append(String.format("T%s;", argumentGenericBase + currentParameter));
superFunNMethodDescriptor.append(objectSignature); superFunNMethodDescriptor.append(objectSignature);
} }
superFunNClassSignature.append(String.format("%s:%s>%s", returnGeneric, objectSignature, objectSignature));
if (numReturnTypes > 0) { if (numReturnTypes > 0) {
superFunNClassSignature.append(String.format("%s:%s>%s", returnGeneric, objectSignature, objectSignature));
superFunNMethodSignature.append(String.format(")T%s;", returnGeneric)); superFunNMethodSignature.append(String.format(")T%s;", returnGeneric));
superFunNMethodDescriptor.append(String.format(")%s", objectSignature)); superFunNMethodDescriptor.append(String.format(")%s", objectSignature));
} else { } else {
superFunNClassSignature = new StringBuilder(objectSignature);
superFunNMethodSignature.append(")V"); superFunNMethodSignature.append(")V");
superFunNMethodDescriptor.append(")V"); superFunNMethodDescriptor.append(")V");
} }

View File

@@ -67,8 +67,8 @@ public class LanguageServerInterface {
compiler.writeClassFile(bytecode, path.getParent().resolve("out").toFile(), false); compiler.writeClassFile(bytecode, path.getParent().resolve("out").toFile(), false);
return new LanguageServerTransferObject(tiResults, parsedSource, "", compiler.getGeneratedGenerics()); return new LanguageServerTransferObject(tiResults, parsedSource, "", compiler.getGeneratedGenerics());
} catch (Exception e) { }catch (Exception e){
throw new RuntimeException(e.getMessage(), e); throw new RuntimeException(e.getMessage());
} }
} }

View File

@@ -111,7 +111,7 @@ public class SyntaxTreeGenerator {
this.allmodifiers.put(Modifier.toString(Modifier.INTERFACE), Modifier.INTERFACE); this.allmodifiers.put(Modifier.toString(Modifier.INTERFACE), Modifier.INTERFACE);
this.allmodifiers.put("sealed", 4096); this.allmodifiers.put("sealed", 4096);
this.allmodifiers.put("non-sealed", 8192); this.allmodifiers.put("non-sealed", 8192);
this.allmodifiers.put("default", 0); // Doesn't exist this.allmodifiers.put("default", 16384);
this.allmodifiers.put("strictfp", 32768); this.allmodifiers.put("strictfp", 32768);
this.compiler = compiler; this.compiler = compiler;

View File

@@ -168,7 +168,7 @@ public class TypeGenerator {
if (generics.contains(name)) { if (generics.contains(name)) {
return new GenericRefType(name, offset); return new GenericRefType(name, offset);
} else { } else {
Pattern p = Pattern.compile("Fun(Void|VoidImpl|Wrapper)?(\\d+)[$][$]"); // TODO Regex shenanigans Pattern p = Pattern.compile("Fun(\\d+)[$][$]");
Matcher m = p.matcher(name); Matcher m = p.matcher(name);
if (m.matches()) {// es ist FunN$$-Type if (m.matches()) {// es ist FunN$$-Type
return new RefType(new JavaClassName(name), convert(typeArguments, reg, generics), offset); return new RefType(new JavaClassName(name), convert(typeArguments, reg, generics), offset);

View File

@@ -846,6 +846,13 @@ public class ASTToTargetAST {
compiler.usedFunNSuperTypes.add(params.size()); compiler.usedFunNSuperTypes.add(params.size());
var code = FunNGenerator.generateSuperBytecode(params.size() - 1, returnType != null ? 1 : 0); var code = FunNGenerator.generateSuperBytecode(params.size() - 1, returnType != null ? 1 : 0);
var superClassName = FunNGenerator.getSuperClassName(params.size() - 1, returnType != null ? 1 : 0); var superClassName = FunNGenerator.getSuperClassName(params.size() - 1, returnType != null ? 1 : 0);
try {
compiler.classLoader.findClass(superClassName);
} catch (ClassNotFoundException e) {
try {
compiler.classLoader.loadClass(superClassName, code);
} catch (LinkageError ignored) {}
}
compiler.auxiliaries.put(superClassName, code); compiler.auxiliaries.put(superClassName, code);
} }
FunNGenerator.GenericParameters gep = null; FunNGenerator.GenericParameters gep = null;

View File

@@ -161,6 +161,7 @@ public class StatementToTargetExpression implements ASTVisitor {
@Override @Override
public void visit(FieldVar fieldVar) { public void visit(FieldVar fieldVar) {
var isStatic = false;
var type = converter.convert(fieldVar.receiver.getType()); var type = converter.convert(fieldVar.receiver.getType());
var clazz = converter.compiler.getClass(new JavaClassName(type.name())); var clazz = converter.compiler.getClass(new JavaClassName(type.name()));
var field = clazz.getField(fieldVar.fieldVarName).orElseThrow(); var field = clazz.getField(fieldVar.fieldVarName).orElseThrow();

View File

@@ -8,42 +8,42 @@ public sealed interface TargetLiteral extends TargetExpression {
record BooleanLiteral(Boolean value) implements TargetLiteral { record BooleanLiteral(Boolean value) implements TargetLiteral {
@Override @Override
public TargetType type() { public TargetType type() {
return TargetType.boolean_; return TargetType.Boolean;
} }
} }
record CharLiteral(Character value) implements TargetLiteral { record CharLiteral(Character value) implements TargetLiteral {
@Override @Override
public TargetType type() { public TargetType type() {
return TargetType.char_; return TargetType.Char;
} }
} }
record IntLiteral(Integer value) implements TargetLiteral { record IntLiteral(Integer value) implements TargetLiteral {
@Override @Override
public TargetType type() { public TargetType type() {
return TargetType.int_; return TargetType.Integer;
} }
} }
record LongLiteral(Long value) implements TargetLiteral { record LongLiteral(Long value) implements TargetLiteral {
@Override @Override
public TargetType type() { public TargetType type() {
return TargetType.long_; return TargetType.Long;
} }
} }
record FloatLiteral(Float value) implements TargetLiteral { record FloatLiteral(Float value) implements TargetLiteral {
@Override @Override
public TargetType type() { public TargetType type() {
return TargetType.float_; return TargetType.Float;
} }
} }
record DoubleLiteral(Double value) implements TargetLiteral { record DoubleLiteral(Double value) implements TargetLiteral {
@Override @Override
public TargetType type() { public TargetType type() {
return TargetType.double_; return TargetType.Double;
} }
} }

View File

@@ -33,10 +33,4 @@ public record TargetFunNType(String name, List<TargetType> funNParams, List<Targ
public String getInternalName() { public String getInternalName() {
return name; return name;
} }
@Override
public String toSignature() {
var args = FunNGenerator.getArguments(funNParams);
return "LFun" + args.size() + "$$" + TargetSpecializedType.signatureParameters(funNParams) + ";";
}
} }

View File

@@ -8,20 +8,14 @@ public sealed interface TargetSpecializedType extends TargetType permits TargetF
@Override @Override
default String toSignature() { default String toSignature() {
String ret = "L" + getInternalName(); String ret = "L" + getInternalName();
ret += signatureParameters(params()); if (!params().isEmpty()) {
ret += ";";
return ret;
}
static String signatureParameters(List<TargetType> params) {
var ret = "";
if (!params.isEmpty()) {
ret += "<"; ret += "<";
for (var param : params) { for (var param : params()) {
ret += param.toSignature(); ret += param.toSignature();
} }
ret += ">"; ret += ">";
} }
ret += ";";
return ret; return ret;
} }

View File

@@ -935,7 +935,7 @@ public class TYPEStmt implements StatementVisitor {
@Override @Override
public void visit(Yield aYield) { public void visit(Yield aYield) {
aYield.retexpr.accept(this); aYield.retexpr.accept(this);
constraintsSet.addUndConstraint(new Pair(aYield.getType(), switchStack.peek().getType(), PairOperator.SMALLERDOT, loc(aYield.getOffset()))); constraintsSet.addUndConstraint(new Pair(aYield.getType(), switchStack.peek().getType(), PairOperator.EQUALSDOT, loc(aYield.getOffset())));
// TODO Auto-generated method stub // TODO Auto-generated method stub
} }
} }

View File

@@ -735,17 +735,8 @@ public class TestComplete {
public void testSwitchRecordLiteral() throws Exception { public void testSwitchRecordLiteral() throws Exception {
var classFiles = generateClassFiles(createClassLoader(), "PatternMatchingLiteralStyle.jav"); var classFiles = generateClassFiles(createClassLoader(), "PatternMatchingLiteralStyle.jav");
var clazz = classFiles.get("SwitchOverload"); var clazz = classFiles.get("SwitchOverload");
var record = classFiles.get("R");
var rctor = record.getDeclaredConstructor(String.class);
var instance = clazz.getDeclaredConstructor().newInstance();
var m = clazz.getDeclaredMethod("m", record);
assertEquals(10, m.invoke(instance, rctor.newInstance("test")));
assertEquals(20, m.invoke(instance, rctor.newInstance("foo")));
assertEquals(0, m.invoke(instance, rctor.newInstance("???")));
} }
@Test @Test
public void testSwitchCaseHeritageDetection() throws Exception { public void testSwitchCaseHeritageDetection() throws Exception {
var classFiles = generateClassFiles(createClassLoader(), "SwitchCaseHeritageDetection.jav"); var classFiles = generateClassFiles(createClassLoader(), "SwitchCaseHeritageDetection.jav");
@@ -1485,42 +1476,4 @@ public class TestComplete {
var m = clazz.getDeclaredMethod("main"); var m = clazz.getDeclaredMethod("main");
m.invoke(null); m.invoke(null);
} }
@Disabled("Doesn't work yet")
@Test
public void testBug378() throws Exception {
var classFiles = generateClassFiles(createClassLoader(), "Bug378Main.jav");
var clazz = classFiles.get("Bug378Main");
var main = clazz.getDeclaredMethod("main", List.class);
main.invoke(null, List.of());
}
@Test
public void testBug379() throws Exception {
var classFiles = generateClassFiles(createClassLoader(), "Bug379.jav");
var clazz = classFiles.get("Bug379");
clazz.getDeclaredConstructor().newInstance();
}
@Test
public void testBug380() throws Exception {
var classFiles = generateClassFiles(createClassLoader(), "Bug380.jav");
var clazz = classFiles.get("Bug380");
clazz.getDeclaredConstructor().newInstance();
}
@Test
public void testBug382() throws Exception {
var classFiles = generateClassFiles(createClassLoader(), "Bug382.jav");
var clazz = classFiles.get("Bug382");
clazz.getDeclaredMethod("main", List.class).invoke(null, List.of());
}
@Test
public void testBug383() throws Exception {
var classFiles = generateClassFiles(createClassLoader(), "Bug383.jav");
var clazz = classFiles.get("Bug383");
clazz.getDeclaredMethod("main", List.class).invoke(null, List.of());
// TODO This logs output that we should validate
}
} }