Compare commits

..

36 Commits

Author SHA1 Message Date
71555486b0 Change internals of Codegen to use boxed types by default
Some checks failed
SonarQube Scan / SonarQube Trigger (push) Failing after 1m48s
Fix #379
Add a validator step, fix invalid attributes
2025-09-27 11:08:27 +02:00
4048902442 Work on #378
All checks were successful
SonarQube Scan / SonarQube Trigger (push) Successful in 2m45s
2025-09-25 17:24:32 +02:00
acce38e8b1 Fix #372 by using package name
All checks were successful
SonarQube Scan / SonarQube Trigger (push) Successful in 3m50s
Build and Test with Maven / Build-and-test-with-Maven (push) Successful in 1m38s
2025-09-19 12:16:26 +02:00
dbd7f4fcfe Signature and Descriptor confusion resolved, fix #377
All checks were successful
SonarQube Scan / SonarQube Trigger (push) Successful in 2m43s
2025-09-19 12:01:01 +02:00
9114642370 Undo test breakage
All checks were successful
SonarQube Scan / SonarQube Trigger (push) Successful in 3m48s
2025-09-18 18:56:08 +02:00
8ac0f96bd6 Fix #376
Some checks failed
SonarQube Scan / SonarQube Trigger (push) Has been cancelled
2025-09-18 18:54:39 +02:00
pl@gohorb.ba-horb.de
b29eb71238 Merge branch 'master' of https://gitea.hb.dhbw-stuttgart.de/JavaTX/JavaCompilerCore
All checks were successful
SonarQube Scan / SonarQube Trigger (push) Successful in 3m40s
2025-09-18 16:43:46 +02:00
pl@gohorb.ba-horb.de
e9ce071e2b modified: src/main/java/de/dhbwstuttgart/parser/SyntaxTreeGenerator/StatementGenerator.java
Die Parameter von Lambda-Ausdruecken wurden mit der Variance 1 belegt.
2025-09-18 16:39:12 +02:00
3567bae0d7 Decouple Generics from ASTToTargetAST
All checks were successful
SonarQube Scan / SonarQube Trigger (push) Successful in 3m16s
2025-09-17 17:19:23 +02:00
9160c99cf2 README.md hinzugefügt
All checks were successful
SonarQube Scan / SonarQube Trigger (push) Successful in 2m42s
2025-08-01 13:58:56 +00:00
c72a14cab3 Add libraries to sonar
All checks were successful
SonarQube Scan / SonarQube Trigger (push) Successful in 2m45s
2025-07-31 18:03:50 +02:00
10bb5d1d11 Typo
All checks were successful
SonarQube Scan / SonarQube Trigger (push) Successful in 3m30s
2025-07-31 17:25:31 +02:00
2842fc5069 Readd workflow for tests on other branches
Some checks failed
SonarQube Scan / SonarQube Trigger (push) Has been cancelled
2025-07-31 17:24:21 +02:00
5c5e0bd1e9 split up
All checks were successful
SonarQube Scan / SonarQube Trigger (push) Successful in 2m42s
2025-07-31 15:17:18 +02:00
3d81318e01 Different property
Some checks failed
SonarQube Scan / SonarQube Trigger (push) Failing after 2m4s
2025-07-31 15:11:43 +02:00
53e2c20608 Debug log
Some checks failed
SonarQube Scan / SonarQube Trigger (push) Failing after 2m12s
2025-07-31 15:03:53 +02:00
86e467fd82 Add test directory?
Some checks failed
SonarQube Scan / SonarQube Trigger (push) Failing after 2m2s
2025-07-31 15:00:21 +02:00
25b14e9342 Fix encoding issues
Some checks failed
SonarQube Scan / SonarQube Trigger (push) Failing after 2m39s
2025-07-31 14:53:17 +02:00
d0de0b31e4 Add test metadata
Some checks failed
SonarQube Scan / SonarQube Trigger (push) Failing after 2m49s
2025-07-31 14:42:41 +02:00
dd180524b2 Remove duplicate workflow
All checks were successful
SonarQube Scan / SonarQube Trigger (push) Successful in 2m40s
2025-07-31 14:35:04 +02:00
b3744bf5f7 Fix argLine not being passed to test
Some checks failed
Build and Test with Maven / Build-and-test-with-Maven (push) Has been cancelled
SonarQube Scan / SonarQube Trigger (push) Successful in 3m4s
2025-07-31 14:22:06 +02:00
fda16978c2 Correct workflow
Some checks failed
Build and Test with Maven / Build-and-test-with-Maven (push) Has been cancelled
SonarQube Scan / SonarQube Trigger (push) Successful in 3m22s
2025-07-31 14:07:03 +02:00
a485cd8fa6 Add jacoco
Some checks failed
Build and Test with Maven / Build-and-test-with-Maven (push) Has been cancelled
SonarQube Scan / SonarQube Trigger (push) Has been cancelled
2025-07-31 14:05:42 +02:00
f8c708f0f4 Add classes directory
Some checks failed
Build and Test with Maven / Build-and-test-with-Maven (push) Has been cancelled
SonarQube Scan / SonarQube Trigger (push) Successful in 1m50s
2025-07-31 13:54:59 +02:00
28d9946bbb Add debug logging
Some checks failed
Build and Test with Maven / Build-and-test-with-Maven (push) Has been cancelled
SonarQube Scan / SonarQube Trigger (push) Failing after 1m7s
2025-07-31 13:51:46 +02:00
7b4ca8f177 Add src
Some checks failed
Build and Test with Maven / Build-and-test-with-Maven (push) Has been cancelled
SonarQube Scan / SonarQube Trigger (push) Failing after 1m7s
2025-07-31 13:40:42 +02:00
b879d7743d Compile with maven
Some checks failed
Build and Test with Maven / Build-and-test-with-Maven (push) Has been cancelled
SonarQube Scan / SonarQube Trigger (push) Failing after 1m8s
2025-07-31 13:31:56 +02:00
e26a43b400 Add project key
Some checks failed
Build and Test with Maven / Build-and-test-with-Maven (push) Has been cancelled
SonarQube Scan / SonarQube Trigger (push) Failing after 31s
2025-07-31 13:28:23 +02:00
5deed725ae Fix again
Some checks failed
Build and Test with Maven / Build-and-test-with-Maven (push) Has been cancelled
SonarQube Scan / SonarQube Trigger (push) Failing after 26s
2025-07-31 12:16:17 +02:00
8ae15f9d41 Update again
Some checks failed
SonarQube Scan / SonarQube Trigger (push) Has been cancelled
Build and Test with Maven / Build-and-test-with-Maven (push) Has been cancelled
2025-07-31 12:15:11 +02:00
8c8e088612 Use newer scanner
Some checks failed
Build and Test with Maven / Build-and-test-with-Maven (push) Has been cancelled
SonarQube Scan / SonarQube Trigger (push) Failing after 20s
2025-07-31 12:06:21 +02:00
2814c6538e Add jdk 17
Some checks failed
Build and Test with Maven / Build-and-test-with-Maven (push) Successful in 1m48s
SonarQube Scan / SonarQube Trigger (push) Failing after 24s
2025-07-31 11:56:58 +02:00
dcbc29b49b Nano
Some checks failed
Build and Test with Maven / Build-and-test-with-Maven (push) Has been cancelled
SonarQube Scan / SonarQube Trigger (push) Failing after 13s
2025-07-31 11:49:01 +02:00
05033bcb9d Sonar
Some checks failed
Build and Test with Maven / Build-and-test-with-Maven (push) Has been cancelled
2025-07-31 11:48:03 +02:00
814f5dd5fa Add main method #372
All checks were successful
Build and Test with Maven / Build-and-test-with-Maven (push) Successful in 1m40s
2025-07-23 16:00:37 +02:00
24ca985ccc Fix #373
All checks were successful
Build and Test with Maven / Build-and-test-with-Maven (push) Successful in 1m17s
2025-07-23 14:41:57 +02:00
38 changed files with 569 additions and 259 deletions

View File

@@ -1,5 +1,8 @@
name: Build and Test with Maven name: Build and Test with Maven
on: [push] on:
push:
branches-ignore:
- master
jobs: jobs:
Build-and-test-with-Maven: Build-and-test-with-Maven:

View File

@@ -0,0 +1,45 @@
on:
push:
branches:
- master
pull_request:
types: [opened, synchronize, reopened]
name: SonarQube Scan
jobs:
sonarqube:
name: SonarQube Trigger
runs-on: ubuntu-latest
steps:
- name: Checking out
uses: actions/checkout@v4
with:
# Disabling shallow clone is recommended for improving relevancy of reporting
fetch-depth: 0
- name: Install maven
run: |
apt update
apt install -y maven
- name: Install java
uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: '24'
cache: 'maven'
- name: Compile project
run: |
mvn clean dependency:copy-dependencies verify
- name: SonarQube Scan
uses: SonarSource/sonarqube-scan-action@v5.3.0
env:
SONAR_HOST_URL: ${{ secrets.SONARQUBE_HOST }}
SONAR_TOKEN: ${{ secrets.SONARQUBE_TOKEN }}
with:
args: >
-Dsonar.projectKey=Java-TX
-Dsonar.sources=src/main/java
-Dsonar.tests=src/test/java
-Dsonar.junit.reportPaths=target/test-reports
-Dsonar.java.binaries=target/classes
-Dsonar.java.libraries=target/dependency/*.jar
-Dsonar.coverage.jacoco.xmlReportPaths=target/site/jacoco/jacoco.xml

7
README.md Normal file
View File

@@ -0,0 +1,7 @@
## Java-TX Compiler
[![Lines of Code](https://gitea.hb.dhbw-stuttgart.de/sonarqube/api/project_badges/measure?project=Java-TX&metric=ncloc&token=sqb_d4a372fca7a6b86441243728a6ea5f88183db5eb)](https://gitea.hb.dhbw-stuttgart.de/sonarqube/dashboard?id=Java-TX)
[![Coverage](https://gitea.hb.dhbw-stuttgart.de/sonarqube/api/project_badges/measure?project=Java-TX&metric=coverage&token=sqb_d4a372fca7a6b86441243728a6ea5f88183db5eb)](https://gitea.hb.dhbw-stuttgart.de/sonarqube/dashboard?id=Java-TX)
[![Quality Gate Status](https://gitea.hb.dhbw-stuttgart.de/sonarqube/api/project_badges/measure?project=Java-TX&metric=alert_status&token=sqb_d4a372fca7a6b86441243728a6ea5f88183db5eb)](https://gitea.hb.dhbw-stuttgart.de/sonarqube/dashboard?id=Java-TX)
Work in Progress Java-TX Compiler repository!

26
pom.xml
View File

@@ -44,10 +44,34 @@ 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>
<plugins> <plugins>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.13</version>
<executions>
<execution>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>report</id>
<phase>prepare-package</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId> <artifactId>maven-compiler-plugin</artifactId>
@@ -65,7 +89,7 @@ http://maven.apache.org/maven-v4_0_0.xsd">
<configuration> <configuration>
<redirectTestOutputToFile>true</redirectTestOutputToFile> <redirectTestOutputToFile>true</redirectTestOutputToFile>
<reportsDirectory>${project.build.directory}/test-reports</reportsDirectory> <reportsDirectory>${project.build.directory}/test-reports</reportsDirectory>
<argLine>--enable-preview</argLine> <argLine>${argLine} --enable-preview</argLine>
<trimStackTrace>false</trimStackTrace> <trimStackTrace>false</trimStackTrace>
<excludes> <excludes>
<exclude>**/JavaTXCompilerTest.java</exclude> <exclude>**/JavaTXCompilerTest.java</exclude>

View File

@@ -6,7 +6,7 @@ import java.util.stream.Stream;
public class Bug325 { public class Bug325 {
public main() { public main() {
List<Integer> list = new ArrayList<>(List.of(1,2,3,4,5)); var list = new ArrayList<>(List.of(1,2,3,4,5));
var func = x -> x*2; var func = x -> x*2;
return list.stream().map(func).toList(); return list.stream().map(func).toList();
} }

View File

@@ -0,0 +1,17 @@
import java.lang.Boolean;
import java.lang.Integer;
import java.lang.System;
import java.io.PrintStream;
import java.lang.Character;
public class Bug373 {
public static main() {
System.out.println(true);
System.out.println(false);
System.out.println(1);
System.out.println(1l);
System.out.println(1.0);
System.out.println(1.0f);
System.out.println('a');
}
}

View File

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

View File

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

View File

@@ -0,0 +1,24 @@
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

@@ -0,0 +1,14 @@
import java.lang.Object;
import java.lang.System;
import java.lang.Iterable;
import java.io.PrintStream;
import java.util.List;
import java.lang.String;
class Main {
static main(args) {
for (var arg : args) {
System.out.println(arg);
}
}
}

View File

@@ -9,7 +9,9 @@ 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.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.*;
@@ -125,34 +127,36 @@ 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);
} }
private void boxPrimitive(State state, TargetType type) { private void boxPrimitive(State state, TargetType type) {
if (type instanceof TargetExtendsWildcard ew) type = ew.innerType();
var mv = state.mv; var mv = state.mv;
if (type.equals(TargetType.Boolean) || type.equals(TargetType.boolean_)) { if (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) || type.equals(TargetType.byte_)) { } else if (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) || type.equals(TargetType.double_)) { } else if (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) || type.equals(TargetType.long_)) { } else if (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.Integer) || type.equals(TargetType.int_)) { } else if (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) || type.equals(TargetType.float_)) { } else if (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) || type.equals(TargetType.short_)) { } else if (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) || type.equals(TargetType.char_)) { } else if (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);
} }
} }
private void unboxPrimitive(State state, TargetType type) { private void unboxPrimitive(State state, TargetType type) {
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)) {
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Boolean", "booleanValue", "()Z", false); mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Boolean", "booleanValue", "()Z", false);
@@ -183,9 +187,11 @@ 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);
} }
@@ -200,9 +206,11 @@ 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);
} }
@@ -228,62 +236,85 @@ public class Codegen {
} }
private void convertTo(State state, TargetType source, TargetType dest) { private void convertTo(State state, TargetType source, TargetType dest) {
var mv = state.mv; if (source instanceof TargetExtendsWildcard ew) source = ew.innerType();
if (dest instanceof TargetExtendsWildcard ew) dest = ew.innerType();
if (source.equals(dest)) if (source.equals(dest))
return; return;
if (source.equals(TargetType.Long)) {
if (dest.equals(TargetType.Integer)) { 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());
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); mv.visitInsn(L2I);
} else if (dest.equals(TargetType.Float)) else if (dest.equals(TargetType.float_))
mv.visitInsn(L2F); mv.visitInsn(L2F);
else if (dest.equals(TargetType.Double)) else if (dest.equals(TargetType.double_))
mv.visitInsn(L2D); 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); mv.visitInsn(L2I);
convertTo(state, TargetType.Integer, dest); convertTo(state, TargetType.int_, dest);
} }
} else if (source.equals(TargetType.Float)) { } else if (source.equals(TargetType.float_)) {
if (dest.equals(TargetType.Integer)) if (dest.equals(TargetType.int_))
mv.visitInsn(F2I); mv.visitInsn(F2I);
else if (dest.equals(TargetType.Double)) else if (dest.equals(TargetType.double_))
mv.visitInsn(F2D); mv.visitInsn(F2D);
else if (dest.equals(TargetType.Long)) else if (dest.equals(TargetType.long_))
mv.visitInsn(F2L); 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); mv.visitInsn(F2I);
convertTo(state, TargetType.Integer, dest); convertTo(state, TargetType.int_, dest);
} }
} else if (source.equals(TargetType.Double)) { } else if (source.equals(TargetType.double_)) {
if (dest.equals(TargetType.Integer)) if (dest.equals(TargetType.int_))
mv.visitInsn(D2I); mv.visitInsn(D2I);
else if (dest.equals(TargetType.Float)) else if (dest.equals(TargetType.float_))
mv.visitInsn(D2F); mv.visitInsn(D2F);
else if (dest.equals(TargetType.Long)) else if (dest.equals(TargetType.long_))
mv.visitInsn(D2L); 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); mv.visitInsn(D2I);
convertTo(state, TargetType.Integer, dest); convertTo(state, TargetType.int_, 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.int_)) {
if (dest.equals(TargetType.Byte)) if (dest.equals(TargetType.byte_))
mv.visitInsn(I2B); mv.visitInsn(I2B);
else if (dest.equals(TargetType.Char)) else if (dest.equals(TargetType.char_))
mv.visitInsn(I2C); mv.visitInsn(I2C);
else if (dest.equals(TargetType.Short)) else if (dest.equals(TargetType.short_))
mv.visitInsn(I2S); mv.visitInsn(I2S);
else if (dest.equals(TargetType.Long)) else if (dest.equals(TargetType.long_))
mv.visitInsn(I2L); mv.visitInsn(I2L);
else if (dest.equals(TargetType.Float)) else if (dest.equals(TargetType.float_))
mv.visitInsn(I2F); mv.visitInsn(I2F);
else if (dest.equals(TargetType.Double)) else if (dest.equals(TargetType.double_))
mv.visitInsn(I2D); mv.visitInsn(I2D);
} else if (source.equals(TargetType.boolean_)) {
unboxPrimitive(state, dest);
} else if (isFunctionalInterface(source) && isFunctionalInterface(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);
} else if (!(dest instanceof TargetGenericType)) { return;
//boxPrimitive(state, source); }
mv.visitTypeInsn(CHECKCAST, dest.getInternalName());
unboxPrimitive(state, dest); if (!(origDest instanceof TargetPrimitiveType)) {
if (dest instanceof TargetPrimitiveType)
boxPrimitive(state, dest);
else boxPrimitive(state, source);
} }
} }
@@ -343,9 +374,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(), add.type()); convertTo(state, add.left().type(), TargetType.toPrimitive(add.type()));
generate(state, add.right()); generate(state, add.right());
convertTo(state, add.right().type(), add.type()); convertTo(state, add.right().type(), TargetType.toPrimitive(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);
@@ -358,6 +389,7 @@ 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());
@@ -369,9 +401,9 @@ public class Codegen {
} }
case Sub sub: { case Sub sub: {
generate(state, sub.left()); generate(state, sub.left());
convertTo(state, sub.left().type(), op.type()); convertTo(state, sub.left().type(), TargetType.toPrimitive(op.type()));
generate(state, sub.right()); generate(state, sub.right());
convertTo(state, sub.right().type(), op.type()); convertTo(state, sub.right().type(), TargetType.toPrimitive(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);
@@ -384,13 +416,14 @@ 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(), op.type()); convertTo(state, div.left().type(), TargetType.toPrimitive(op.type()));
generate(state, div.right()); generate(state, div.right());
convertTo(state, div.right().type(), op.type()); convertTo(state, div.right().type(), TargetType.toPrimitive(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);
@@ -403,13 +436,14 @@ 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(), op.type()); convertTo(state, mul.left().type(), TargetType.toPrimitive(op.type()));
generate(state, mul.right()); generate(state, mul.right());
convertTo(state, mul.right().type(), op.type()); convertTo(state, mul.right().type(), TargetType.toPrimitive(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);
@@ -422,13 +456,14 @@ 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(), op.type()); convertTo(state, rem.left().type(), TargetType.toPrimitive(op.type()));
generate(state, rem.right()); generate(state, rem.right());
convertTo(state, rem.right().type(), op.type()); convertTo(state, rem.right().type(), TargetType.toPrimitive(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);
@@ -441,6 +476,7 @@ 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: {
@@ -448,14 +484,18 @@ 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;
} }
@@ -463,47 +503,54 @@ 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(), op.type()); convertTo(state, band.left().type(), TargetType.toPrimitive(op.type()));
generate(state, band.right()); generate(state, band.right());
convertTo(state, band.right().type(), op.type()); convertTo(state, band.right().type(), TargetType.toPrimitive(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(), op.type()); convertTo(state, bor.left().type(), TargetType.toPrimitive(op.type()));
generate(state, bor.right()); generate(state, bor.right());
convertTo(state, bor.right().type(), op.type()); convertTo(state, bor.right().type(), TargetType.toPrimitive(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(), op.type()); convertTo(state, xor.left().type(), TargetType.toPrimitive(op.type()));
generate(state, xor.right()); generate(state, xor.right());
convertTo(state, xor.right().type(), op.type()); convertTo(state, xor.right().type(), TargetType.toPrimitive(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: {
@@ -512,44 +559,47 @@ public class Codegen {
} }
case Shl shl: { case Shl shl: {
generate(state, shl.left()); generate(state, shl.left());
convertTo(state, shl.left().type(), op.type()); convertTo(state, shl.left().type(), TargetType.toPrimitive(op.type()));
generate(state, shl.right()); generate(state, shl.right());
convertTo(state, shl.right().type(), op.type()); convertTo(state, shl.right().type(), TargetType.toPrimitive(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(), op.type()); convertTo(state, shr.left().type(), TargetType.toPrimitive(op.type()));
generate(state, shr.right()); generate(state, shr.right());
convertTo(state, shr.right().type(), op.type()); convertTo(state, shr.right().type(), TargetType.toPrimitive(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(), op.type()); convertTo(state, ushr.left().type(), TargetType.toPrimitive(op.type()));
generate(state, ushr.right()); generate(state, ushr.right());
convertTo(state, ushr.right().type(), op.type()); convertTo(state, ushr.right().type(), TargetType.toPrimitive(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 = largerType(greater.left().type(), greater.right().type()); var type = TargetType.toPrimitive(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);
@@ -557,12 +607,12 @@ public class Codegen {
break; break;
} }
case Less less: { case Less less: {
var type = largerType(less.left().type(), less.right().type()); var type = TargetType.toPrimitive(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);
@@ -570,12 +620,12 @@ public class Codegen {
break; break;
} }
case GreaterOrEqual greaterOrEqual: { case GreaterOrEqual greaterOrEqual: {
var type = largerType(greaterOrEqual.left().type(), greaterOrEqual.right().type()); var type = TargetType.toPrimitive(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);
@@ -583,12 +633,12 @@ public class Codegen {
break; break;
} }
case LessOrEqual lessOrEqual: { case LessOrEqual lessOrEqual: {
var type = largerType(lessOrEqual.left().type(), lessOrEqual.right().type()); var type = TargetType.toPrimitive(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);
@@ -596,30 +646,30 @@ public class Codegen {
break; break;
} }
case Equal equal: { case Equal equal: {
var type = largerType(equal.left().type(), equal.right().type()); var type = TargetType.toPrimitive(largerType(equal.left().type(), equal.right().type()));
if (type.equals(TargetType.Long)) { if (type.equals(TargetType.long_)) {
generateRelationalOperator(state, equal, type, LCMP, IFEQ); generateRelationalOperator(state, equal, TargetType.long_, LCMP, IFEQ);
} else if (type.equals(TargetType.Float)) { } else if (type.equals(TargetType.float_)) {
generateRelationalOperator(state, equal, type, FCMPL, IFEQ); generateRelationalOperator(state, equal, TargetType.float_, FCMPL, IFEQ);
} else if (type.equals(TargetType.Double)) { } else if (type.equals(TargetType.double_)) {
generateRelationalOperator(state, equal, type, DCMPL, IFEQ); generateRelationalOperator(state, equal, TargetType.double_, DCMPL, IFEQ);
} else if (type.equals(TargetType.Char) || type.equals(TargetType.Short) || type.equals(TargetType.Byte) || type.equals(TargetType.Integer) || type.equals(TargetType.Boolean)) { } else if (type.equals(TargetType.char_) || type.equals(TargetType.short_) || type.equals(TargetType.byte_) || type.equals(TargetType.int_) || type.equals(TargetType.boolean_)) {
generateRelationalOperator(state, equal, type, IF_ICMPEQ); generateRelationalOperator(state, equal, TargetType.int_, 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 = largerType(notEqual.left().type(), notEqual.right().type()); var type = TargetType.toPrimitive(largerType(notEqual.left().type(), notEqual.right().type()));
if (type.equals(TargetType.Long)) { if (type.equals(TargetType.long_)) {
generateRelationalOperator(state, notEqual, type, LCMP, IFNE); generateRelationalOperator(state, notEqual, TargetType.long_, LCMP, IFNE);
} else if (type.equals(TargetType.Float)) { } else if (type.equals(TargetType.float_)) {
generateRelationalOperator(state, notEqual, type, FCMPL, IFNE); generateRelationalOperator(state, notEqual, TargetType.float_, FCMPL, IFNE);
} else if (type.equals(TargetType.Double)) { } else if (type.equals(TargetType.double_)) {
generateRelationalOperator(state, notEqual, type, DCMPL, IFNE); generateRelationalOperator(state, notEqual, TargetType.double_, DCMPL, IFNE);
} else if (type.equals(TargetType.Char) || type.equals(TargetType.Short) || type.equals(TargetType.Byte) || type.equals(TargetType.Integer)) { } else if (type.equals(TargetType.char_) || type.equals(TargetType.short_) || type.equals(TargetType.byte_) || type.equals(TargetType.int_) || type.equals(TargetType.boolean_)) {
generateRelationalOperator(state, notEqual, type, IF_ICMPNE); generateRelationalOperator(state, notEqual, TargetType.int_, IF_ICMPNE);
} else { } else {
generateRelationalOperator(state, notEqual, type, IF_ACMPNE); generateRelationalOperator(state, notEqual, type, IF_ACMPNE);
} }
@@ -638,7 +688,7 @@ public class Codegen {
} else if (op.expr() instanceof TargetFieldVar fieldVar) { } else if (op.expr() instanceof TargetFieldVar fieldVar) {
generate(state, fieldVar.left()); generate(state, fieldVar.left());
mv.visitInsn(SWAP); mv.visitInsn(SWAP);
mv.visitFieldInsn(PUTFIELD, fieldVar.owner().getInternalName(), fieldVar.right(), fieldVar.type().toSignature()); mv.visitFieldInsn(PUTFIELD, fieldVar.owner().getInternalName(), fieldVar.right(), fieldVar.type().toDescriptor());
} }
} }
@@ -650,6 +700,7 @@ 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))
@@ -658,9 +709,11 @@ public class Codegen {
mv.visitInsn(LNEG); mv.visitInsn(LNEG);
else else
mv.visitInsn(INEG); mv.visitInsn(INEG);
boxPrimitive(state, TargetType.boolean_);
} }
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);
@@ -668,93 +721,86 @@ public class Codegen {
mv.visitInsn(ICONST_M1); mv.visitInsn(ICONST_M1);
mv.visitInsn(IXOR); mv.visitInsn(IXOR);
} }
boxPrimitive(state, TargetType.boolean_);
} }
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, preIncrement.type()); boxPrimitive(state, TargetType.toPrimitive(op.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, preDecrement.type()); boxPrimitive(state, TargetType.toPrimitive(op.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());
if (postIncrement.type().equals(TargetType.Float)) {
mv.visitInsn(DUP); mv.visitInsn(DUP);
convertTo(state, postIncrement.expr().type(), TargetType.toPrimitive(op.type()));
if (postIncrement.type().equals(TargetType.Float)) {
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, postIncrement.type()); boxPrimitive(state, TargetType.toPrimitive(op.type()));
afterIncDec(state, postIncrement); afterIncDec(state, postIncrement);
} }
case TargetUnaryOp.PostDecrement postDecrement -> { case TargetUnaryOp.PostDecrement postDecrement -> {
generate(state, postDecrement.expr()); generate(state, postDecrement.expr());
if (postDecrement.type().equals(TargetType.Float)) {
mv.visitInsn(DUP); mv.visitInsn(DUP);
convertTo(state, postDecrement.expr().type(), TargetType.toPrimitive(op.type()));
if (postDecrement.type().equals(TargetType.Float)) {
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, postDecrement.type()); boxPrimitive(state, TargetType.toPrimitive(op.type()));
afterIncDec(state, postDecrement); afterIncDec(state, postDecrement);
} }
} }
@@ -801,7 +847,7 @@ public class Codegen {
var handle = new Handle(state.isStatic ? H_INVOKESTATIC : H_INVOKEVIRTUAL, clazz.getName(), impl.name(), implSignature.getDescriptor(), false); var handle = new Handle(state.isStatic ? H_INVOKESTATIC : H_INVOKEVIRTUAL, clazz.getName(), impl.name(), implSignature.getDescriptor(), false);
var params = new ArrayList<TargetType>(); var params = new ArrayList<TargetType>();
if(!state.isStatic) params.add(new TargetRefType(clazz.qualifiedName().getClassName())); if(!state.isStatic) params.add(new TargetRefType(clazz.qualifiedName().toString()));
params.addAll(lambda.captures().stream().map(mp -> mp.pattern().type()).toList()); params.addAll(lambda.captures().stream().map(mp -> mp.pattern().type()).toList());
if (!state.isStatic) if (!state.isStatic)
@@ -940,7 +986,7 @@ public class Codegen {
mv.visitInsn(DUP); mv.visitInsn(DUP);
else else
mv.visitInsn(DUP_X1); mv.visitInsn(DUP_X1);
mv.visitFieldInsn(dot.isStatic() ? PUTSTATIC : PUTFIELD, dot.owner().getInternalName(), dot.right(), fieldType.toSignature()); mv.visitFieldInsn(dot.isStatic() ? PUTSTATIC : PUTFIELD, dot.owner().getInternalName(), dot.right(), fieldType.toDescriptor());
} }
default -> throw new CodeGenException("Invalid assignment"); default -> throw new CodeGenException("Invalid assignment");
} }
@@ -951,14 +997,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().toSignature()); 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: {
@@ -974,11 +1020,14 @@ 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());
else convertTo(state, _for.termination().type(), TargetType.boolean_);
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;
@@ -1010,6 +1059,7 @@ 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();
@@ -1040,6 +1090,7 @@ 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);
@@ -1047,6 +1098,7 @@ 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);
@@ -1064,11 +1116,10 @@ public class Codegen {
if (state.returnType instanceof TargetPrimitiveType) { if (state.returnType instanceof TargetPrimitiveType) {
generate(state, ret.expression()); generate(state, ret.expression());
unboxPrimitive(state, state.returnType); convertTo(state, ret.expression().type(), state.returnType);
mv.visitInsn(findReturnCode(state.returnType)); mv.visitInsn(findReturnCode(state.returnType));
} else { } else {
generate(state, ret.expression()); generate(state, ret.expression());
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);
} }
@@ -1120,8 +1171,6 @@ 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) // Decay FunN if (call.owner() instanceof TargetFunNType) // Decay FunN
@@ -1134,11 +1183,13 @@ 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:
@@ -1161,6 +1212,7 @@ 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);
@@ -1214,6 +1266,7 @@ 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;
} }
@@ -1408,7 +1461,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();
} }
@@ -1421,12 +1474,12 @@ public class Codegen {
throw new CodeGenException("Couldn't find suitable field accessor for '" + type.name() + "'"); throw new CodeGenException("Couldn't find suitable field accessor for '" + type.name() + "'");
var field = clazz.getFieldDecl().get(i); var field = clazz.getFieldDecl().get(i);
var fieldType = converter.convert(field.getType()); var fieldType = converter.convert(field.getType());
state.mv.visitMethodInsn(INVOKEVIRTUAL, type.getInternalName(), field.getName(), "()" + fieldType.toSignature(), false); state.mv.visitMethodInsn(INVOKEVIRTUAL, type.getInternalName(), field.getName(), "()" + fieldType.toDescriptor(), false);
} }
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);
@@ -1447,13 +1500,14 @@ public class Codegen {
} }
if (pat instanceof TargetExpressionPattern ep) { if (pat instanceof TargetExpressionPattern ep) {
var cur = state.createVariable(pat.type()); var cur = state.createVariable(TargetType.toWrapper(pat.type()));
state.mv.visitVarInsn(ASTORE, cur.index); state.mv.visitVarInsn(ASTORE, cur.index);
var expr = new Equal(pat.type(), new TargetLocalVar(cur.type, cur.name), ep.expression()); var expr = new Equal(pat.type(), new TargetLocalVar(cur.type, cur.name), ep.expression());
generate(state, expr); generate(state, expr);
var cont = new Label(); var cont = new Label();
unboxPrimitive(state, TargetType.Boolean);
state.mv.visitJumpInsn(IFNE, cont); state.mv.visitJumpInsn(IFNE, cont);
for (var i = 0; i < depth - 1; i++) { for (var i = 0; i < depth - 1; i++) {
state.mv.visitInsn(POP); state.mv.visitInsn(POP);
@@ -1526,7 +1580,7 @@ public class Codegen {
//if ((access & ACC_PRIVATE) == 0 && (access & ACC_PROTECTED) == 0) // TODO Implement access modifiers properly //if ((access & ACC_PRIVATE) == 0 && (access & ACC_PROTECTED) == 0) // TODO Implement access modifiers properly
// access |= ACC_PUBLIC; // access |= ACC_PUBLIC;
cw.visitField(access, field.name(), field.type().toSignature(), field.type().toDescriptor(), null); cw.visitField(access, field.name(), field.type().toDescriptor(), field.type().toSignature(), null);
} }
private void generateStaticConstructor(TargetMethod constructor) { private void generateStaticConstructor(TargetMethod constructor) {
@@ -1597,8 +1651,27 @@ public class Codegen {
generateMethod(method, null); generateMethod(method, null);
} }
private void generateMainMethod() {
var mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "main", "([Ljava/lang/String;)V", null, null);
mv.visitCode();
mv.visitVarInsn(ALOAD, 0);
mv.visitMethodInsn(INVOKESTATIC, "java/util/List", "of", "([Ljava/lang/Object;)Ljava/util/List;", true);
mv.visitMethodInsn(INVOKESTATIC, new TargetRefType(clazz.qualifiedName().toString()).getInternalName(), "main", "(Ljava/util/List;)V", false);
mv.visitInsn(RETURN);
mv.visitMaxs(0, 0);
mv.visitEnd();
}
private void generateMethod(TargetMethod method, State parent) { private void generateMethod(TargetMethod method, State parent) {
var access = method.access(); var access = method.access();
var params = method.signature().parameters();
if (method.name().equals("main") && method.isStatic() && params.size() == 1 &&
params.getFirst().pattern().type().equals(new TargetRefType("java.util.List", List.of(new TargetRefType("java.lang.String"))))) {
generateMainMethod();
}
if (method.block() == null) if (method.block() == null)
access |= ACC_ABSTRACT; access |= ACC_ABSTRACT;
if (clazz instanceof TargetInterface) if (clazz instanceof TargetInterface)
@@ -1640,12 +1713,14 @@ public class Codegen {
if (!generics.isEmpty()) { if (!generics.isEmpty()) {
ret += "<"; ret += "<";
for (var generic : generics) { for (var generic : generics) {
ret += generic.name() + ":" + generic.bound().toDescriptor(); ret += generic.name() + ":" + generic.bound().toSignature();
} }
ret += ">"; ret += ">";
} }
if (clazz.superType() != null) if (clazz.superType() != null)
ret += clazz.superType().toDescriptor(); 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();
} }
@@ -1748,8 +1823,12 @@ 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);
@@ -1757,7 +1836,7 @@ public class Codegen {
cw2.visitEnd(); cw2.visitEnd();
var bytes = cw2.toByteArray(); var bytes = cw2.toByteArray();
converter.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. // TODO These class loading shenanigans happen in a few places, the tests load the classes individually.
// Instead we should just look at the folder. // Instead we should just look at the folder.
@@ -1771,6 +1850,9 @@ public class Codegen {
} }
cw.visitEnd(); cw.visitEnd();
ClassReader cr = new ClassReader(cw.toByteArray());
System.out.println("Checking class " + className);
CheckClassAdapter.verify(cr, false, new PrintWriter(System.err));
return cw.toByteArray(); return cw.toByteArray();
} }
@@ -1800,7 +1882,7 @@ public class Codegen {
bootstrapArgs[1] = String.join(";", clazz.fields().stream().map(TargetField::name).toArray(String[]::new)); bootstrapArgs[1] = String.join(";", clazz.fields().stream().map(TargetField::name).toArray(String[]::new));
for (var i = 0; i < clazz.fields().size(); i++) { for (var i = 0; i < clazz.fields().size(); i++) {
var field = clazz.fields().get(i); var field = clazz.fields().get(i);
var fieldRef = new Handle(H_GETFIELD, clazz.getName(), field.name(), field.type().toSignature(), false); var fieldRef = new Handle(H_GETFIELD, clazz.getName(), field.name(), field.type().toDescriptor(), false);
bootstrapArgs[i + 2] = fieldRef; bootstrapArgs[i + 2] = fieldRef;
} }

View File

@@ -98,7 +98,7 @@ public class FunNGenerator {
} }
private static String applySignature(TargetType a) { return a.toSignature(); } private static String applySignature(TargetType a) { return a.toSignature(); }
private static String applyNameDescriptor(TargetType a){ return a instanceof TargetGenericType ? "LTPH;" : String.format("%s", applySignature(a)); } private static String applyNameDescriptor(TargetType a){ return a instanceof TargetGenericType ? "LTPH;" : String.format("%s", a.toDescriptor()); }
public static String encodeType(TargetType type) { public static String encodeType(TargetType type) {
if (type == null) return VOID; if (type == null) return VOID;

View File

@@ -2,6 +2,7 @@
package de.dhbwstuttgart.core; package de.dhbwstuttgart.core;
import de.dhbwstuttgart.bytecode.Codegen; import de.dhbwstuttgart.bytecode.Codegen;
import de.dhbwstuttgart.bytecode.FunNGenerator;
import de.dhbwstuttgart.environment.CompilationEnvironment; import de.dhbwstuttgart.environment.CompilationEnvironment;
import de.dhbwstuttgart.environment.DirectoryClassLoader; import de.dhbwstuttgart.environment.DirectoryClassLoader;
import de.dhbwstuttgart.exceptions.DebugException; import de.dhbwstuttgart.exceptions.DebugException;
@@ -73,6 +74,11 @@ public class JavaTXCompiler {
public final List<File> classPath; public final List<File> classPath;
private final File outputPath; private final File outputPath;
public final Map<String, FunNGenerator.GenericParameters> usedFunN = new HashMap<>();
public final Set<Integer> usedFunNSuperTypes = new HashSet<>();
public Map<String, byte[]> auxiliaries = new HashMap<>();
public DirectoryClassLoader getClassLoader() { public DirectoryClassLoader getClassLoader() {
return classLoader; return classLoader;
} }
@@ -646,7 +652,7 @@ public class JavaTXCompiler {
} }
generatedGenerics.put(sf, converter.javaGenerics()); generatedGenerics.put(sf, converter.javaGenerics());
converter.generateFunNTypes(); converter.generateFunNTypes();
converter.auxiliaries.forEach((name, source) -> { auxiliaries.forEach((name, source) -> {
generatedClasses.put(new JavaClassName(name), source); generatedClasses.put(new JavaClassName(name), source);
}); });
return generatedClasses; return generatedClasses;

View File

@@ -30,7 +30,7 @@ public class CompilationEnvironment {
public final PackageCrawler packageCrawler; public final PackageCrawler packageCrawler;
/** /**
* Imitiert die Environment beim Aufruf des JavaCompilers auf einer Menge von java-Dateien Die Environment enth<EFBFBD>lt automatisch die Java Standard Library * Imitiert die Environment beim Aufruf des JavaCompilers auf einer Menge von java-Dateien Die Environment enthält automatisch die Java Standard Library
* *
* @param sourceFiles die zu kompilierenden Dateien * @param sourceFiles die zu kompilierenden Dateien
*/ */

View File

@@ -150,7 +150,7 @@ public class StatementGenerator {
} else { } else {
type = methodparameters? type = methodparameters?
TypePlaceholder.fresh(fp.getStart(), 1, false) TypePlaceholder.fresh(fp.getStart(), 1, false)
: TypePlaceholder.fresh(fp.getStart()); : TypePlaceholder.fresh(fp.getStart(), 1, false);
} }
ret.add(new FormalParameter(paramName, type, fp.getStart())); ret.add(new FormalParameter(paramName, type, fp.getStart()));
localVars.put(paramName, type); localVars.put(paramName, type);
@@ -1065,7 +1065,7 @@ public class StatementGenerator {
List<Pattern> parameterList = new ArrayList<>(); List<Pattern> parameterList = new ArrayList<>();
for (IdentifierContext identifier : lambdaParams.identifier()) { for (IdentifierContext identifier : lambdaParams.identifier()) {
Token offset = identifier.getStart(); Token offset = identifier.getStart();
parameterList.add(new FormalParameter(identifier.getText(), TypePlaceholder.fresh(offset), offset)); parameterList.add(new FormalParameter(identifier.getText(), TypePlaceholder.fresh(offset, 1, false), offset));
} }
params = new ParameterList(parameterList, lambdaParams.getStart()); params = new ParameterList(parameterList, lambdaParams.getStart());
} else if (lambdaParams.formalParameterList() != null) { } else if (lambdaParams.formalParameterList() != null) {
@@ -1075,7 +1075,7 @@ public class StatementGenerator {
List<Pattern> parameterList = new ArrayList<>(); List<Pattern> parameterList = new ArrayList<>();
for (LambdaLVTIParameterContext param : lambdaParams.lambdaLVTIList().lambdaLVTIParameter()) { for (LambdaLVTIParameterContext param : lambdaParams.lambdaLVTIList().lambdaLVTIParameter()) {
Token offset = param.getStart(); Token offset = param.getStart();
parameterList.add(new FormalParameter(param.identifier().getText(), TypePlaceholder.fresh(offset), offset)); parameterList.add(new FormalParameter(param.identifier().getText(), TypePlaceholder.fresh(offset, 1, false), offset));
} }
params = new ParameterList(parameterList, lambdaParams.getStart()); params = new ParameterList(parameterList, lambdaParams.getStart());
} else { } else {

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", 16384); this.allmodifiers.put("default", 0); // Doesn't exist
this.allmodifiers.put("strictfp", 32768); this.allmodifiers.put("strictfp", 32768);
this.compiler = compiler; this.compiler = compiler;

View File

@@ -41,7 +41,7 @@ public class JavaClassName {
} }
/** /**
* Gibt von einem Klassennamen nur den Namen der Klasse zur<EFBFBD>ck * Gibt von einem Klassennamen nur den Namen der Klasse zurück
* Beispiel: * Beispiel:
* java.lang.Object wird zu: Object * java.lang.Object wird zu: Object
*/ */

View File

@@ -5,7 +5,7 @@ import de.dhbwstuttgart.exceptions.NotImplementedException;
import java.util.*; import java.util.*;
/** /**
* Speichert die Klassen f<EFBFBD>r einen bestimmten Projektscope * Speichert die Klassen für einen bestimmten Projektscope
*/ */
public class JavaClassRegistry{ public class JavaClassRegistry{
final Map<JavaClassName, Integer> existingClasses = new HashMap<>(); final Map<JavaClassName, Integer> existingClasses = new HashMap<>();

View File

@@ -6,10 +6,12 @@ import de.dhbwstuttgart.syntaxtree.type.GenericRefType;
import de.dhbwstuttgart.syntaxtree.type.RefType; import de.dhbwstuttgart.syntaxtree.type.RefType;
import de.dhbwstuttgart.syntaxtree.type.TypePlaceholder; import de.dhbwstuttgart.syntaxtree.type.TypePlaceholder;
import de.dhbwstuttgart.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric; import de.dhbwstuttgart.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric;
import de.dhbwstuttgart.target.tree.TargetGeneric;
import org.antlr.v4.runtime.Token; import org.antlr.v4.runtime.Token;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
import java.util.*; import java.util.*;
import java.util.stream.Collectors;
/** /**
* Stellt jede Art von Klasse dar. Auch abstrakte Klassen und Interfaces * Stellt jede Art von Klasse dar. Auch abstrakte Klassen und Interfaces
@@ -31,6 +33,7 @@ public class ClassOrInterface extends SyntaxTreeNode implements TypeScope {
private List<RefType> implementedInterfaces; private List<RefType> implementedInterfaces;
private List<RefType> permittedSubtypes; private List<RefType> permittedSubtypes;
private List<Constructor> constructors; private List<Constructor> constructors;
private Set<GenericTypeVar> userDefinedGenerics;
public ClassOrInterface(int modifiers, JavaClassName name, List<Field> fielddecl, Optional<Constructor> fieldInitializations, Optional<Method> staticInitializer, List<Method> methods, List<Constructor> constructors, GenericDeclarationList genericClassParameters, RefType superClass, Boolean isInterface, Boolean isFunctionalInterface, List<RefType> implementedInterfaces, List<RefType> permittedSubtypes, Token offset, String fileName) { public ClassOrInterface(int modifiers, JavaClassName name, List<Field> fielddecl, Optional<Constructor> fieldInitializations, Optional<Method> staticInitializer, List<Method> methods, List<Constructor> constructors, GenericDeclarationList genericClassParameters, RefType superClass, Boolean isInterface, Boolean isFunctionalInterface, List<RefType> implementedInterfaces, List<RefType> permittedSubtypes, Token offset, String fileName) {
super(offset); super(offset);
@@ -199,4 +202,22 @@ public class ClassOrInterface extends SyntaxTreeNode implements TypeScope {
public int hashCode() { public int hashCode() {
return Objects.hash(name); return Objects.hash(name);
} }
public Set<GenericTypeVar> getUserDefinedGenerics() {
if (this.userDefinedGenerics != null) return this.userDefinedGenerics;
var genericsIter = getGenerics().iterator();
if (genericsIter.hasNext()) {
// Add empty set of generics to cache so that it doesn't try to calculate it later
this.userDefinedGenerics = new HashSet<>();
while (genericsIter.hasNext()) {
var next = genericsIter.next();
userDefinedGenerics.add(next);
}
} else {
this.userDefinedGenerics = new HashSet<>();
}
return this.userDefinedGenerics;
}
} }

View File

@@ -5,8 +5,10 @@ import java.util.*;
import de.dhbwstuttgart.parser.NullToken; import de.dhbwstuttgart.parser.NullToken;
import de.dhbwstuttgart.parser.scope.JavaClassName; import de.dhbwstuttgart.parser.scope.JavaClassName;
import de.dhbwstuttgart.target.generate.ASTToTargetAST;
import de.dhbwstuttgart.typeinference.constraints.ConstraintSet; import de.dhbwstuttgart.typeinference.constraints.ConstraintSet;
import de.dhbwstuttgart.typeinference.assumptions.TypeInferenceInformation; import de.dhbwstuttgart.typeinference.assumptions.TypeInferenceInformation;
import de.dhbwstuttgart.typeinference.result.ResultSet;
//import sun.security.x509.X509CertInfo; //import sun.security.x509.X509CertInfo;
public class SourceFile extends SyntaxTreeNode { public class SourceFile extends SyntaxTreeNode {
@@ -18,6 +20,7 @@ public class SourceFile extends SyntaxTreeNode {
private boolean isGenerated; private boolean isGenerated;
public List<ClassOrInterface> availableClasses = new ArrayList<>(); public List<ClassOrInterface> availableClasses = new ArrayList<>();
public List<ASTToTargetAST.Generics> generics = new ArrayList<>();
/** /**
* Die SourceFile repräsntiert eine zu einem Syntaxbaum eingelesene Java-Datei. * Die SourceFile repräsntiert eine zu einem Syntaxbaum eingelesene Java-Datei.
@@ -40,6 +43,10 @@ public class SourceFile extends SyntaxTreeNode {
this.imports = new HashSet<>(sf.imports); this.imports = new HashSet<>(sf.imports);
} }
public void addResultSet(ResultSet rs) {
}
public void setPackageName(String packageName) { public void setPackageName(String packageName) {
this.pkgName = packageName; this.pkgName = packageName;
} }

View File

@@ -36,7 +36,6 @@ public class ASTToTargetAST {
public Generics generics; public Generics generics;
public List<Generics> currentMethodOverloads; public List<Generics> currentMethodOverloads;
final Map<ClassOrInterface, Set<GenericTypeVar>> userDefinedGenerics = new HashMap<>();
final Map<Method, Set<SignaturePair>> tphsInMethods = new HashMap<>(); final Map<Method, Set<SignaturePair>> tphsInMethods = new HashMap<>();
private Method currentMethod; private Method currentMethod;
@@ -61,8 +60,10 @@ public class ASTToTargetAST {
} }
public record Generics(JavaGenerics javaGenerics, TxGenerics txGenerics) { public record Generics(JavaGenerics javaGenerics, TxGenerics txGenerics) {
public Generics(JavaTXCompiler compiler, ResultSet set) {
this(new JavaGenerics(compiler, set), new TxGenerics(compiler, set));
}
} }
public IByteArrayClassLoader classLoader; public IByteArrayClassLoader classLoader;
protected SourceFile sourceFile; protected SourceFile sourceFile;
@@ -81,9 +82,9 @@ public class ASTToTargetAST {
all = new ArrayList<>(); all = new ArrayList<>();
for (var set : resultSets) { for (var set : resultSets) {
all.add(new Generics(new JavaGenerics(this, set), new TxGenerics(this, set))); all.add(new Generics(compiler, set));
} }
this.generics = all.get(0); this.generics = all.getFirst();
} }
public void addSignaturePair(TypePlaceholder signature, RefTypeOrTPHOrWildcardOrGeneric parameter) { public void addSignaturePair(TypePlaceholder signature, RefTypeOrTPHOrWildcardOrGeneric parameter) {
@@ -93,9 +94,13 @@ public class ASTToTargetAST {
} }
Optional<Method> findMethod(ClassOrInterface owner, String name, List<TargetType> argumentList) { Optional<Method> findMethod(ClassOrInterface owner, String name, List<TargetType> argumentList) {
return findMethod(owner, name, argumentList, this.generics.javaGenerics, this.compiler);
}
public static Optional<Method> findMethod(ClassOrInterface owner, String name, List<TargetType> argumentList, GenerateGenerics generics, JavaTXCompiler compiler) {
Optional<Method> method = Optional.empty(); Optional<Method> method = Optional.empty();
while (method.isEmpty()) { while (method.isEmpty()) {
method = owner.getMethods().stream().filter(m -> m.name.equals(name) && parameterEquals(m.getParameterList(), argumentList)).findFirst(); method = owner.getMethods().stream().filter(m -> m.name.equals(name) && parameterEquals(m.getParameterList(), argumentList, generics)).findFirst();
if (owner.getClassName().toString().equals("java.lang.Object")) break; if (owner.getClassName().toString().equals("java.lang.Object")) break;
owner = compiler.getClass(owner.getSuperClass().getName()); owner = compiler.getClass(owner.getSuperClass().getName());
} }
@@ -103,16 +108,16 @@ public class ASTToTargetAST {
} }
Optional<Constructor> findConstructor(ClassOrInterface owner, List<TargetType> argumentList) { Optional<Constructor> findConstructor(ClassOrInterface owner, List<TargetType> argumentList) {
return owner.getConstructors().stream().filter(c -> parameterEquals(c.getParameterList(), argumentList)).findFirst(); return owner.getConstructors().stream().filter(c -> parameterEquals(c.getParameterList(), argumentList, generics.javaGenerics)).findFirst();
} }
boolean parameterEquals(ParameterList parameterList, List<TargetType> arguments) { static boolean parameterEquals(ParameterList parameterList, List<TargetType> arguments, GenerateGenerics generics) {
var pars = parameterList.getFormalparalist(); var pars = parameterList.getFormalparalist();
if (pars.size() != arguments.size()) if (pars.size() != arguments.size())
return false; return false;
for (var i = 0; i < pars.size(); i++) { for (var i = 0; i < pars.size(); i++) {
var type1 = convert(pars.get(i).getType(), generics.javaGenerics); var type1 = generics.getTargetType(pars.get(i).getType());
var type2 = arguments.get(i); var type2 = arguments.get(i);
if (type1 instanceof TargetGenericType) if (type1 instanceof TargetGenericType)
return true; return true;
@@ -350,19 +355,14 @@ public class ASTToTargetAST {
Set<TargetGeneric> javaGenerics = new HashSet<>(); Set<TargetGeneric> javaGenerics = new HashSet<>();
Set<TargetGeneric> txGenerics = new HashSet<>(); Set<TargetGeneric> txGenerics = new HashSet<>();
var genericsIter = input.getGenerics().iterator(); var userDefinedGenerics = input.getUserDefinedGenerics();
if (genericsIter.hasNext()) { if (!userDefinedGenerics.isEmpty()) {
// Add empty set of generics to cache so that it doesn't try to calculate it later // Add empty set of generics to cache so that it doesn't try to calculate it later
var userDefinedGenerics = new HashSet<GenericTypeVar>(); for (var generic : userDefinedGenerics) {
this.userDefinedGenerics.put(input, userDefinedGenerics); // TODO Support multiple bouds
while (genericsIter.hasNext()) { javaGenerics.add(new TargetGeneric(generic.getName(), convert(generic.getBounds().getFirst())));
var next = genericsIter.next();
userDefinedGenerics.add(next);
// TODO Support multiple bounds
javaGenerics.add(new TargetGeneric(next.getName(), convert(next.getBounds().get(0))));
} }
} else { } else {
this.userDefinedGenerics.put(input, new HashSet<>());
// Generate generics only if there are no user defined ones // Generate generics only if there are no user defined ones
javaGenerics = convert(generics.javaGenerics.generics(input), generics.javaGenerics); javaGenerics = convert(generics.javaGenerics.generics(input), generics.javaGenerics);
txGenerics = convert(generics.txGenerics.generics(input), generics.txGenerics); txGenerics = convert(generics.txGenerics.generics(input), generics.txGenerics);
@@ -424,7 +424,7 @@ public class ASTToTargetAST {
} }
private List<TargetConstructor> convert(ClassOrInterface currentClass, Constructor input, TargetBlock fieldInitializer) { private List<TargetConstructor> convert(ClassOrInterface currentClass, Constructor input, TargetBlock fieldInitializer) {
generics = all.get(0); generics = all.getFirst();
List<TargetConstructor> result = new ArrayList<>(); List<TargetConstructor> result = new ArrayList<>();
Set<List<MethodParameter>> parameterSet = new HashSet<>(); Set<List<MethodParameter>> parameterSet = new HashSet<>();
this.currentMethod = input; this.currentMethod = input;
@@ -468,13 +468,6 @@ public class ASTToTargetAST {
} }
} }
private TargetType unwrap(TargetType type) {
if (type instanceof TargetRefType ref) {
if (!ref.params().isEmpty()) return new TargetRefType(ref.name());
}
return type;
}
private TargetExpression generatePatternOverloadsRec(int offset, TargetExpression switchExpr, List<TargetLocalVar> params, List<TargetPattern> patterns, List<TargetMethod> methods, TargetType classType) { private TargetExpression generatePatternOverloadsRec(int offset, TargetExpression switchExpr, List<TargetLocalVar> params, List<TargetPattern> patterns, List<TargetMethod> methods, TargetType classType) {
if (methods.isEmpty()) throw new DebugException("Couldn't find a candidate for switch overloading"); if (methods.isEmpty()) throw new DebugException("Couldn't find a candidate for switch overloading");
if (methods.size() == 1) { if (methods.size() == 1) {
@@ -745,11 +738,6 @@ public class ASTToTargetAST {
return new TargetField(input.modifier, convert(input.getType(), generics.javaGenerics), input.getName()); return new TargetField(input.modifier, convert(input.getType(), generics.javaGenerics), input.getName());
} }
private final Map<String, FunNGenerator.GenericParameters> usedFunN = new HashMap<>();
private final Set<Integer> usedFunNSuperTypes = new HashSet<>();
public Map<String, byte[]> auxiliaries = new HashMap<>();
public TargetType convert(RefTypeOrTPHOrWildcardOrGeneric input) { public TargetType convert(RefTypeOrTPHOrWildcardOrGeneric input) {
return convert(input, generics.javaGenerics); return convert(input, generics.javaGenerics);
} }
@@ -818,20 +806,24 @@ public class ASTToTargetAST {
} }
public void generateFunNTypes() { public void generateFunNTypes() {
for (var entry : usedFunN.entrySet()) { for (var entry : compiler.usedFunN.entrySet()) {
var gep = entry.getValue(); var gep = entry.getValue();
var superInterfaces = usedFunN.values().stream() var superInterfaces = compiler.usedFunN.values().stream()
.filter(g -> !g.equals(gep)) .filter(g -> !g.equals(gep))
.filter(genericParameters -> isSubtype(gep, genericParameters)) .filter(genericParameters -> isSubtype(gep, genericParameters))
.map(FunNGenerator::getSpecializedClassName) .map(FunNGenerator::getSpecializedClassName)
.toList(); .toList();
var code = FunNGenerator.generateSpecializedBytecode(gep, superInterfaces); var code = FunNGenerator.generateSpecializedBytecode(gep, superInterfaces);
auxiliaries.put(entry.getKey(), code); compiler.auxiliaries.put(entry.getKey(), code);
} }
} }
protected TargetType convert(RefTypeOrTPHOrWildcardOrGeneric input, GenerateGenerics generics) { public TargetType convert(RefTypeOrTPHOrWildcardOrGeneric input, GenerateGenerics generics) {
return convert(input, generics, compiler);
}
public static TargetType convert(RefTypeOrTPHOrWildcardOrGeneric input, GenerateGenerics generics, JavaTXCompiler compiler) {
return input.acceptTV(new TypeVisitor<>() { return input.acceptTV(new TypeVisitor<>() {
@Override @Override
public TargetType visit(RefType refType) { public TargetType visit(RefType refType) {
@@ -843,31 +835,31 @@ public class ASTToTargetAST {
} }
var params = refType.getParaList().stream().map(type -> { var params = refType.getParaList().stream().map(type -> {
return convert(type, generics); return convert(type, generics, compiler);
}).toList(); }).toList();
if (name.matches("Fun\\d+\\$\\$")) { // TODO This seems like a bad idea if (name.matches("Fun\\d+\\$\\$")) { // TODO This seems like a bad idea
var returnType = FunNGenerator.getReturnType(params); var returnType = FunNGenerator.getReturnType(params);
var className = FunNGenerator.getSpecializedClassName(FunNGenerator.getArguments(params), returnType); var className = FunNGenerator.getSpecializedClassName(FunNGenerator.getArguments(params), returnType);
if (!usedFunNSuperTypes.contains(params.size())) { if (!compiler.usedFunNSuperTypes.contains(params.size())) {
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 { try {
classLoader.findClass(superClassName); compiler.classLoader.findClass(superClassName);
} catch (ClassNotFoundException e) { } catch (ClassNotFoundException e) {
try { try {
classLoader.loadClass(superClassName, code); compiler.classLoader.loadClass(superClassName, code);
} catch (LinkageError ignored) {} } catch (LinkageError ignored) {}
} }
auxiliaries.put(superClassName, code); compiler.auxiliaries.put(superClassName, code);
} }
FunNGenerator.GenericParameters gep = null; FunNGenerator.GenericParameters gep = null;
if (!usedFunN.containsKey(className)) { if (!compiler.usedFunN.containsKey(className)) {
gep = new FunNGenerator.GenericParameters(params, returnType != null ? 1 : 0); gep = new FunNGenerator.GenericParameters(params, returnType != null ? 1 : 0);
usedFunN.put(className, gep); compiler.usedFunN.put(className, gep);
} else { } else {
gep = usedFunN.get(className); gep = compiler.usedFunN.get(className);
} }
return flattenFunNType(params, gep); return flattenFunNType(params, gep);
} }
@@ -876,7 +868,7 @@ public class ASTToTargetAST {
@Override @Override
public TargetType visit(SuperWildcardType superWildcardType) { public TargetType visit(SuperWildcardType superWildcardType) {
return new TargetSuperWildcard(convert(superWildcardType.getInnerType(), generics)); return new TargetSuperWildcard(convert(superWildcardType.getInnerType(), generics, compiler));
} }
@Override @Override
@@ -886,7 +878,7 @@ public class ASTToTargetAST {
@Override @Override
public TargetType visit(ExtendsWildcardType extendsWildcardType) { public TargetType visit(ExtendsWildcardType extendsWildcardType) {
return new TargetExtendsWildcard(convert(extendsWildcardType.getInnerType(), generics)); return new TargetExtendsWildcard(convert(extendsWildcardType.getInnerType(), generics, compiler));
} }
@Override @Override

View File

@@ -1,5 +1,7 @@
package de.dhbwstuttgart.target.generate; package de.dhbwstuttgart.target.generate;
import de.dhbwstuttgart.core.JavaTXCompiler;
import de.dhbwstuttgart.parser.JavaTXParser;
import de.dhbwstuttgart.parser.NullToken; import de.dhbwstuttgart.parser.NullToken;
import de.dhbwstuttgart.syntaxtree.*; import de.dhbwstuttgart.syntaxtree.*;
import de.dhbwstuttgart.syntaxtree.statement.*; import de.dhbwstuttgart.syntaxtree.statement.*;
@@ -18,7 +20,7 @@ import java.util.stream.Stream;
public abstract class GenerateGenerics { public abstract class GenerateGenerics {
private final ASTToTargetAST astToTargetAST; private final JavaTXCompiler compiler;
public class TPH { public class TPH {
private final TypePlaceholder wrap; private final TypePlaceholder wrap;
@@ -134,8 +136,8 @@ public abstract class GenerateGenerics {
Map<TPH, RefTypeOrTPHOrWildcardOrGeneric> concreteTypes = new HashMap<>(); Map<TPH, RefTypeOrTPHOrWildcardOrGeneric> concreteTypes = new HashMap<>();
Map<TypePlaceholder, TypePlaceholder> equality = new HashMap<>(); Map<TypePlaceholder, TypePlaceholder> equality = new HashMap<>();
GenerateGenerics(ASTToTargetAST astToTargetAST, ResultSet constraints) { GenerateGenerics(JavaTXCompiler compiler, ResultSet constraints) {
this.astToTargetAST = astToTargetAST; this.compiler = compiler;
for (var constraint : constraints.results) { for (var constraint : constraints.results) {
if (constraint instanceof PairTPHsmallerTPH p) { if (constraint instanceof PairTPHsmallerTPH p) {
System.out.println(p.left + " " + p.left.getVariance()); System.out.println(p.left + " " + p.left.getVariance());
@@ -281,7 +283,7 @@ public abstract class GenerateGenerics {
Set<TPH> typeVariablesOfClass, Set<TPH> typeVariablesOfClass,
Set<Pair> result Set<Pair> result
) { ) {
var userDefinedGenericsOfClass = astToTargetAST.userDefinedGenerics.get(owner); var userDefinedGenericsOfClass = owner.getUserDefinedGenerics();
// Type variables with bounds that are also type variables of the method // Type variables with bounds that are also type variables of the method
for (var typeVariable : new HashSet<>(typeVariables)) { for (var typeVariable : new HashSet<>(typeVariables)) {
@@ -329,7 +331,7 @@ public abstract class GenerateGenerics {
if (methodCall.receiver instanceof ExpressionReceiver expressionReceiver) { if (methodCall.receiver instanceof ExpressionReceiver expressionReceiver) {
if (expressionReceiver.expr instanceof This) { if (expressionReceiver.expr instanceof This) {
var optMethod = astToTargetAST.findMethod(owner, methodCall.name, methodCall.signatureArguments().stream().map(astToTargetAST::convert).toList()); var optMethod = ASTToTargetAST.findMethod(owner, methodCall.name, methodCall.signatureArguments().stream().map(x -> getTargetType(x)).toList(), GenerateGenerics.this, compiler);
if (optMethod.isEmpty()) return; if (optMethod.isEmpty()) return;
var method2 = optMethod.get(); var method2 = optMethod.get();
System.out.println("In: " + method.getName() + " Method: " + method2.getName()); System.out.println("In: " + method.getName() + " Method: " + method2.getName());
@@ -1005,8 +1007,8 @@ public abstract class GenerateGenerics {
} }
var type = concreteTypes.get(new TPH(tph)); var type = concreteTypes.get(new TPH(tph));
if (type == null) return new TargetGenericType(tph.getName()); if (type == null) return new TargetGenericType(tph.getName());
return astToTargetAST.convert(type, this); return ASTToTargetAST.convert(type, this, compiler);
} }
return astToTargetAST.convert(in, this); return ASTToTargetAST.convert(in, this, compiler);
} }
} }

View File

@@ -69,8 +69,4 @@ public class GenericsResult {
return this.generics.getType(tph); return this.generics.getType(tph);
return type; return type;
} }
public TargetType resolveTarget(RefTypeOrTPHOrWildcardOrGeneric type) {
return this.generics.getTargetType(type);
}
} }

View File

@@ -1,5 +1,6 @@
package de.dhbwstuttgart.target.generate; package de.dhbwstuttgart.target.generate;
import de.dhbwstuttgart.core.JavaTXCompiler;
import de.dhbwstuttgart.syntaxtree.ClassOrInterface; import de.dhbwstuttgart.syntaxtree.ClassOrInterface;
import de.dhbwstuttgart.syntaxtree.Method; import de.dhbwstuttgart.syntaxtree.Method;
import de.dhbwstuttgart.typeinference.result.ResultSet; import de.dhbwstuttgart.typeinference.result.ResultSet;
@@ -7,8 +8,8 @@ import de.dhbwstuttgart.typeinference.result.ResultSet;
import java.util.Set; import java.util.Set;
final class JavaGenerics extends GenerateGenerics { final class JavaGenerics extends GenerateGenerics {
JavaGenerics(ASTToTargetAST astToTargetAST, ResultSet constraints) { JavaGenerics(JavaTXCompiler compiler, ResultSet constraints) {
super(astToTargetAST, constraints); super(compiler, constraints);
} }
@Override @Override

View File

@@ -161,7 +161,6 @@ 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

@@ -1,5 +1,6 @@
package de.dhbwstuttgart.target.generate; package de.dhbwstuttgart.target.generate;
import de.dhbwstuttgart.core.JavaTXCompiler;
import de.dhbwstuttgart.syntaxtree.ClassOrInterface; import de.dhbwstuttgart.syntaxtree.ClassOrInterface;
import de.dhbwstuttgart.syntaxtree.Method; import de.dhbwstuttgart.syntaxtree.Method;
import de.dhbwstuttgart.typeinference.result.ResultSet; import de.dhbwstuttgart.typeinference.result.ResultSet;
@@ -7,8 +8,8 @@ import de.dhbwstuttgart.typeinference.result.ResultSet;
import java.util.Set; import java.util.Set;
final class TxGenerics extends GenerateGenerics { final class TxGenerics extends GenerateGenerics {
TxGenerics(ASTToTargetAST astToTargetAST, ResultSet constraints) { TxGenerics(JavaTXCompiler compiler, ResultSet constraints) {
super(astToTargetAST, constraints); super(compiler, constraints);
} }
@Override @Override

View File

@@ -36,30 +36,30 @@ public record TargetMethod(int access, String name, TargetBlock block, Signature
public static String getDescriptor(TargetType returnType, TargetType... parameters) { public static String getDescriptor(TargetType returnType, TargetType... parameters) {
String ret = "("; String ret = "(";
for (var parameterType : parameters) { for (var parameterType : parameters) {
ret += parameterType.toSignature(); ret += parameterType.toDescriptor();
} }
ret += ")"; ret += ")";
if (returnType == null) ret += "V"; if (returnType == null) ret += "V";
else ret += returnType.toSignature(); else ret += returnType.toDescriptor();
return ret; return ret;
} }
public static String getSignature(Set<TargetGeneric> generics, List<MethodParameter> parameters, TargetType returnType) { public static String getSignature(Set<TargetGeneric> generics, List<MethodParameter> parameters, TargetType returnType) {
String ret = ""; String ret = "";
if (generics.size() > 0) { if (!generics.isEmpty()) {
ret += "<"; ret += "<";
for (var generic : generics) { for (var generic : generics) {
ret += generic.name() + ":" + generic.bound().toDescriptor(); ret += generic.name() + ":" + generic.bound().toSignature();
} }
ret += ">"; ret += ">";
} }
ret += "("; ret += "(";
for (var param : parameters) { for (var param : parameters) {
ret += param.pattern().type().toDescriptor(); ret += param.pattern().type().toSignature();
} }
ret += ")"; ret += ")";
if (returnType == null) ret += "V"; if (returnType == null) ret += "V";
else ret += returnType.toDescriptor(); else ret += returnType.toSignature();
return ret; return ret;
} }

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.Integer; return TargetType.int_;
} }
} }
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

@@ -3,12 +3,12 @@ package de.dhbwstuttgart.target.tree.type;
public record TargetExtendsWildcard(TargetType innerType) implements TargetType { public record TargetExtendsWildcard(TargetType innerType) implements TargetType {
@Override @Override
public String toSignature() { public String toSignature() {
return innerType.toSignature(); return "+" + innerType.toSignature();
} }
@Override @Override
public String toDescriptor() { public String toDescriptor() {
return "+" + innerType.toDescriptor(); return innerType.toDescriptor();
} }
@Override @Override

View File

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

View File

@@ -2,12 +2,12 @@ package de.dhbwstuttgart.target.tree.type;
public record TargetGenericType(String name) implements TargetType { public record TargetGenericType(String name) implements TargetType {
@Override @Override
public String toSignature() { public String toDescriptor() {
return "Ljava/lang/Object;"; // TODO Use bounds for this? return "Ljava/lang/Object;"; // TODO Use bounds for this?
} }
@Override @Override
public String toDescriptor() { public String toSignature() {
return "T" + getInternalName() + ";"; return "T" + getInternalName() + ";";
} }

View File

@@ -12,11 +12,6 @@ public record TargetRefType(String name, List<TargetType> params) implements Tar
return this.name.replaceAll("\\.", "/"); return this.name.replaceAll("\\.", "/");
} }
@Override
public String toSignature() {
return "L" + getInternalName() + ";";
}
// Type erasure means we need to override hashCode and equals to only consider the name // Type erasure means we need to override hashCode and equals to only consider the name
@Override @Override
public int hashCode() { public int hashCode() {

View File

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

View File

@@ -3,12 +3,12 @@ package de.dhbwstuttgart.target.tree.type;
public record TargetSuperWildcard(TargetType innerType) implements TargetType { public record TargetSuperWildcard(TargetType innerType) implements TargetType {
@Override @Override
public String toSignature() { public String toSignature() {
return innerType.toSignature(); return "-" + innerType.toSignature();
} }
@Override @Override
public String toDescriptor() { public String toDescriptor() {
return "-" + innerType.toDescriptor(); return innerType.toDescriptor();
} }
@Override @Override

View File

@@ -1,6 +1,7 @@
package de.dhbwstuttgart.typeinference.typeAlgo; package de.dhbwstuttgart.typeinference.typeAlgo;
import de.dhbwstuttgart.exceptions.DebugException; import de.dhbwstuttgart.exceptions.DebugException;
import de.dhbwstuttgart.parser.NullToken;
import de.dhbwstuttgart.parser.SourceLoc; import de.dhbwstuttgart.parser.SourceLoc;
import de.dhbwstuttgart.parser.antlr.Java17Parser; import de.dhbwstuttgart.parser.antlr.Java17Parser;
import de.dhbwstuttgart.parser.scope.JavaClassName; import de.dhbwstuttgart.parser.scope.JavaClassName;
@@ -9,15 +10,18 @@ import de.dhbwstuttgart.syntaxtree.factory.ASTFactory;
import de.dhbwstuttgart.syntaxtree.statement.Statement; import de.dhbwstuttgart.syntaxtree.statement.Statement;
import de.dhbwstuttgart.syntaxtree.type.RefType; import de.dhbwstuttgart.syntaxtree.type.RefType;
import de.dhbwstuttgart.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric; import de.dhbwstuttgart.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric;
import de.dhbwstuttgart.target.tree.type.TargetRefType;
import de.dhbwstuttgart.typeinference.assumptions.FieldAssumption; import de.dhbwstuttgart.typeinference.assumptions.FieldAssumption;
import de.dhbwstuttgart.typeinference.assumptions.TypeInferenceBlockInformation; import de.dhbwstuttgart.typeinference.assumptions.TypeInferenceBlockInformation;
import de.dhbwstuttgart.typeinference.assumptions.TypeInferenceInformation; import de.dhbwstuttgart.typeinference.assumptions.TypeInferenceInformation;
import de.dhbwstuttgart.typeinference.constraints.Constraint;
import de.dhbwstuttgart.typeinference.constraints.ConstraintSet; import de.dhbwstuttgart.typeinference.constraints.ConstraintSet;
import de.dhbwstuttgart.typeinference.constraints.Pair; import de.dhbwstuttgart.typeinference.constraints.Pair;
import de.dhbwstuttgart.typeinference.unify.model.PairOperator; import de.dhbwstuttgart.typeinference.unify.model.PairOperator;
import de.dhbwstuttgart.util.BiRelation; import de.dhbwstuttgart.util.BiRelation;
import org.antlr.v4.runtime.Token; import org.antlr.v4.runtime.Token;
import java.lang.reflect.Modifier;
import java.util.*; import java.util.*;
public class TYPE { public class TYPE {
@@ -87,12 +91,25 @@ public class TYPE {
TypeInferenceBlockInformation blockInfo = new TypeInferenceBlockInformation(info.getAvailableClasses(), currentClass, m); TypeInferenceBlockInformation blockInfo = new TypeInferenceBlockInformation(info.getAvailableClasses(), currentClass, m);
TYPEStmt methodScope = new TYPEStmt(blockInfo); TYPEStmt methodScope = new TYPEStmt(blockInfo);
ConstraintSet constraintSet = new ConstraintSet(); ConstraintSet constraintSet = new ConstraintSet();
m.getParameterList().getFormalparalist().forEach(el -> {
if(el instanceof RecordPattern){
constraintSet.addAll(addRecursiveParameterConstraints((RecordPattern) el, blockInfo));
if (m.name.equals("main") && Modifier.isStatic(m.modifier) && m.getParameterList().getFormalparalist().size() == 1) {
// Add constraint for main method
var firstParam = m.getParameterList().getParameterAt(0);
constraintSet.addUndConstraint(new Pair(firstParam.getType(),
new RefType(new JavaClassName("java.util.List"),
List.of(new RefType(new JavaClassName("java.lang.String"), new NullToken())),
new NullToken()),
PairOperator.EQUALSDOT));
} else {
m.getParameterList().getFormalparalist().forEach(el -> {
if (el instanceof RecordPattern rp){
constraintSet.addAll(addRecursiveParameterConstraints(rp, blockInfo));
} }
}); });
}
m.block.accept(methodScope); m.block.accept(methodScope);
constraintSet.addAll(methodScope.getConstraints()); constraintSet.addAll(methodScope.getConstraints());
return constraintSet; return constraintSet;

View File

@@ -1196,6 +1196,15 @@ public class TestComplete {
assertEquals(20, m.invoke(instance)); assertEquals(20, m.invoke(instance));
} }
@Test
public void testMain() throws Exception {
var classFiles = generateClassFiles(createClassLoader(), "Main.jav");
var clazz = classFiles.get("Main");
var m = clazz.getDeclaredMethod("main", List.class);
m.setAccessible(true);
m.invoke(null, List.of("foo", "bar", "baz"));
}
@Test @Test
public void testBug122() throws Exception { public void testBug122() throws Exception {
var classFiles = generateClassFiles(createClassLoader(), "Bug122.jav"); var classFiles = generateClassFiles(createClassLoader(), "Bug122.jav");
@@ -1459,4 +1468,29 @@ public class TestComplete {
var m = clazz.getDeclaredMethod("test"); var m = clazz.getDeclaredMethod("test");
assertEquals(true, m.invoke(null)); assertEquals(true, m.invoke(null));
} }
@Test
public void testBug373() throws Exception {
var classFiles = generateClassFiles(createClassLoader(), "Bug373.jav");
var clazz = classFiles.get("Bug373");
var m = clazz.getDeclaredMethod("main");
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.setAccessible(true);
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();
}
} }

View File

@@ -66,7 +66,7 @@ public class TestCodegen {
converter.generateFunNTypes(); converter.generateFunNTypes();
for (var entry : converter.auxiliaries.entrySet()) { for (var entry : compiler.auxiliaries.entrySet()) {
writeClassFile(entry.getKey(), entry.getValue()); writeClassFile(entry.getKey(), entry.getValue());
} }
} }
@@ -112,7 +112,7 @@ public class TestCodegen {
converter.generateFunNTypes(); converter.generateFunNTypes();
for (var entry : converter.auxiliaries.entrySet()) { for (var entry : compiler.auxiliaries.entrySet()) {
writeClassFile(entry.getKey(), entry.getValue()); writeClassFile(entry.getKey(), entry.getValue());
} }