Compare commits

...

92 Commits

Author SHA1 Message Date
pl@gohorb.ba-horb.de fba7f0ee81 Merge branch 'targetBytecode' of ssh://gohorb.ba-horb.de/bahome/projekt/git/JavaCompilerCore into targetBytecode 2023-11-03 18:42:09 +01:00
pl@gohorb.ba-horb.de e0da2a4c46 modified: Cycle.class
modified:   LambdaRunnable.jav
	modified:   ../../../src/test/java/TestComplete.java
2023-11-03 18:41:17 +01:00
dholle f588ece7c3 Fix up runnable 2023-11-03 15:45:14 +01:00
dholle 9ad5b76542 Fix up bad error handling 2023-11-03 10:26:43 +01:00
dholle 3d2c699964 Fix up functional interface 2023-11-02 15:46:40 +01:00
dholle f95c3c5fcf Fix up method resolution 2023-11-02 15:25:25 +01:00
dholle 4654ecacaf Some changes in how overload resolution works 2023-11-02 13:07:42 +01:00
dholle 1be27746e3 Allow Void as return type for Lambdas 2023-10-31 14:26:43 +01:00
pl@gohorb.ba-horb.de c51190feef Merge branch 'targetBytecode' of ssh://gohorb.ba-horb.de/bahome/projekt/git/JavaCompilerCore into targetBytecode 2023-10-27 21:19:30 +02:00
pl@gohorb.ba-horb.de c4ce97f20c Anpassung zur Integration von Functional Interfaces und FunN$$-Typen
modified:   src/main/java/de/dhbwstuttgart/parser/SyntaxTreeGenerator/FCGenerator.java
	modified:   src/main/java/de/dhbwstuttgart/parser/SyntaxTreeGenerator/SyntaxTreeGenerator.java
	modified:   src/main/java/de/dhbwstuttgart/syntaxtree/ClassOrInterface.java
	modified:   src/main/java/de/dhbwstuttgart/syntaxtree/Record.java
	modified:   src/main/java/de/dhbwstuttgart/syntaxtree/factory/ASTFactory.java
	modified:   src/main/java/de/dhbwstuttgart/typeinference/assumptions/FunNClass.java
	modified:   src/main/java/de/dhbwstuttgart/typeinference/unify/RuleSet.java
	modified:   src/main/java/de/dhbwstuttgart/typeinference/unify/interfaces/IFiniteClosure.java
	modified:   src/main/java/de/dhbwstuttgart/typeinference/unify/model/FiniteClosure.java
	modified:   src/test/java/targetast/ASTToTypedTargetAST.java
2023-10-27 21:17:52 +02:00
dholle 837317c84c Make System.out.println work 2023-10-27 15:28:46 +02:00
pl@gohorb.ba-horb.de df852ef36e Merge branch 'targetBytecode' of ssh://gohorb.ba-horb.de/bahome/projekt/git/JavaCompilerCore into targetBytecode 2023-10-27 14:33:21 +02:00
pl@gohorb.ba-horb.de c00722823a Functional Interfaces und Funn&&-Typen integriert.
modified:   resources/bytecode/javFiles/LambdaRunnable.jav
	modified:   src/main/java/de/dhbwstuttgart/parser/SyntaxTreeGenerator/FCGenerator.java
	modified:   src/main/java/de/dhbwstuttgart/typeinference/unify/RuleSet.java
	modified:   src/main/java/de/dhbwstuttgart/typeinference/unify/TypeUnifyTask.java
	modified:   src/main/java/de/dhbwstuttgart/typeinference/unify/interfaces/IFiniteClosure.java
	modified:   src/main/java/de/dhbwstuttgart/typeinference/unify/interfaces/IRuleSet.java
	modified:   src/main/java/de/dhbwstuttgart/typeinference/unify/model/FiniteClosure.java
	modified:   src/test/java/TestComplete.java
2023-10-27 14:29:27 +02:00
dholle e31f1c59e1 Examples 2023-10-27 14:27:47 +02:00
dholle 5d0d7a6d94 Translate for loop 2023-10-24 17:34:06 +02:00
dholle b372c6ac1c More work on static, references to other classes 2023-10-24 15:17:13 +02:00
dholle 124dea2e58 Static blocks (might be needed for something) 2023-10-24 12:05:19 +02:00
dholle eaef00ff54 Static but no static blocks yet 2023-10-23 16:44:12 +02:00
dholle 892ba5fff0 Add interfaces 2023-10-19 17:02:22 +02:00
dholle 628f1631e8 Allow packages 2023-10-18 16:54:41 +02:00
dholle 0b815950e1 Remove empty files 2023-10-17 12:31:29 +02:00
dholle f10e7e6d72 Merge branch 'targetBytecode' of ssh://gohorb.ba-horb.de:/bahome/projekt/git/JavaCompilerCore into targetBytecode 2023-10-17 12:27:52 +02:00
dholle 700ecf3e5d Changes from weeks ago, needs review 2023-10-17 12:26:40 +02:00
pl@gohorb.ba-horb.de f7c53fc6c3 modified: src/main/java/de/dhbwstuttgart/typeinference/unify/TypeUnifyTask.java
Kommentar "In commit dfd91b5f8b eingefuegt" eingefuegt
2023-10-07 20:30:37 +02:00
pl@gohorb.ba-horb.de 9764ec6db1 Merge branch 'targetBytecode' of ssh://gohorb.ba-horb.de/bahome/projekt/git/JavaCompilerCore into targetBytecode 2023-10-07 07:24:59 +02:00
pl@gohorb.ba-horb.de b21faa30fc new file: S2023_Luca_Trumpfheller.pdf 2023-10-05 15:52:48 +02:00
pl@gohorb.ba-horb.de 87f8b8799e modified: src/test/java/AllgemeinTest.java 2023-10-05 15:49:09 +02:00
Vic Nightfall 769f1bb677 Progress on implementing the basic case 2023-09-01 18:26:01 +02:00
pl@gohorb.ba-horb.de 5623fdc020 Merge branch 'targetBytecode' of ssh://gohorb.ba-horb.de/bahome/projekt/git/JavaCompilerCore into targetBytecode 2023-09-01 17:20:34 +02:00
pl@gohorb.ba-horb.de dfd91b5f8b TESTEN OB DAS SINN MACHT
modified:   src/main/java/de/dhbwstuttgart/typeinference/unify/TypeUnifyTask.java
	modified:   src/test/java/AllgemeinTest.java
2023-09-01 17:18:51 +02:00
Vic Nightfall 3c43978c55 Less general type 2023-09-01 12:51:06 +02:00
Vic Nightfall fb7b51a971 Point out what the goal translation is 2023-09-01 12:34:43 +02:00
dholle 56c360104b TripleTest 2023-08-30 11:28:17 +02:00
dholle e414da3369 Simple record patterns in method headers 2023-08-18 17:15:15 +02:00
dholle 5f1f698530 Refactor 2023-08-18 15:15:40 +02:00
dholle 729e88bc6d Add test for instanceof 2023-08-18 11:35:01 +02:00
dholle bffc7f9f1c Remove TypePattern and replace it with FormalParameter 2023-08-17 16:25:19 +02:00
dholle 011b272af6 Fix missing constraints 2023-08-17 16:15:38 +02:00
dholle ee359da751 Refactor Patterns 2023-08-17 15:56:16 +02:00
dholle 6025e17186 Infer String/Integer for patterns 2023-08-17 15:22:53 +02:00
dholle 93d7aca9e6 Switch on Strings 2023-08-17 14:23:19 +02:00
dholle 677c784b6d Allow single expressions in switch expression 2023-08-17 13:26:30 +02:00
dholle e69a367c33 Add printout 2023-08-17 10:17:09 +02:00
dholle 14d0475d59 Type inference for switch 2023-08-17 09:27:24 +02:00
dholle 762d344e42 Make switches work with set types 2023-08-16 17:13:28 +02:00
dholle be5591f7dc Rename files for macos and windows 2023-08-15 17:17:17 +02:00
dholle 7193f5a646 Workaround for eclipse 2023-08-15 16:52:54 +02:00
dholle f46c2ad0f7 New test case 2023-08-01 14:02:19 +02:00
dholle b0f7a264c2 Implement records 2023-07-31 15:11:35 +02:00
dholle 4f3164a48a Allow the first patterns 2023-07-28 12:05:30 +02:00
dholle be55d661cb Add classic switch 2023-07-27 10:02:28 +02:00
dholle 3de9fde672 Add new target ast nodes and test cases for switch 2023-07-26 15:47:30 +02:00
dholle a0582e918b Merge 2023-07-25 15:06:15 +02:00
pl@gohorb.ba-horb.de 18429d9cf9 Iteration.jav Pair ausgeklammert 2023-07-18 11:45:17 +02:00
pl@gohorb.ba-horb.de b65df7c390 Merge branch 'targetBytecode' of gohorb.ba-horb.de:/bahome/projekt/git/JavaCompilerCore into targetBytecode 2023-07-18 11:44:43 +02:00
luca9913 22d1be5ea4 Fixed expected AST for Instanceof.jav 2023-07-17 19:55:16 +02:00
luca9913 18fc82f036 Merge branch 'patternMatching' of ssh://gohorb.ba-horb.de/bahome/projekt/git/JavaCompilerCore into patternMatching 2023-07-17 19:53:16 +02:00
luca9913 f5b843ec11 Extended instanceOfTest 2023-07-17 19:52:30 +02:00
luca9913 bad5d26969 Extended instanceOfTest 2023-07-17 19:50:58 +02:00
luca9913 951d741d90 Added test for Sealed classe and interface ASTs 2023-07-17 19:38:01 +02:00
luca9913 fe6c9858a2 Finalized test cases for new jav-files 2023-07-17 17:58:39 +02:00
luca9913 1df354d5f1 Modified InstanceOf to use Pattern 2023-07-17 17:49:28 +02:00
luca9913 6119bc92ed Corrected ASTPrinter for RecordPattern 2023-07-15 22:05:34 +02:00
luca9913 e8140b3160 Added method stubs in visitors for new AST nodes 2023-07-15 21:41:50 +02:00
luca9913 75789e574e Modified ASTPrinter to support new AST nodes for tests 2023-07-15 21:41:27 +02:00
luca9913 c0c46e197f Added sealed classes to AST 2023-07-14 08:52:51 +02:00
pl@gohorb.ba-horb.de a0e6df7cfd new file: resources/AllgemeinTest/Twice2.jav
modified:   src/main/java/de/dhbwstuttgart/core/JavaTXCompiler.java
	modified:   src/test/java/AllgemeinTest.java
2023-07-13 15:25:34 +02:00
luca9913 1643412f1b Added nestedPatterns 2023-07-12 21:54:17 +02:00
luca9913 3ed6edc323 Added SwitchExpression to AST 2023-07-12 21:43:50 +02:00
luca9913 fa7a331a66 Beginning of switchExpression for AST 2023-07-11 22:15:35 +02:00
luca9913 939d402b1e Changed GatherNames to add types declared inside of other types to the JavaClassRegistry 2023-07-07 09:24:45 +02:00
luca9913 492cbe48e9 Created RecordPattern & started development with test cases 2023-07-06 22:15:40 +02:00
dholle a17e1f473a Catch linkage error 2023-07-05 15:48:27 +02:00
luca9913 359f3e68ab Added SwitchStmt including Type & GuardedPattern to AST 2023-07-04 15:27:29 +02:00
dholle 5c62191f3b Consider constructors when creating class generics 2023-07-04 12:17:14 +02:00
dholle b04201de42 Don't load classes that get compiled by a source file 2023-07-04 11:40:23 +02:00
pl@gohorb.ba-horb.de a15cbcba7b Merge branch 'targetBytecode' of ssh://gohorb.ba-horb.de/bahome/projekt/git/JavaCompilerCore into targetBytecode 2023-07-03 11:54:30 +02:00
pl@gohorb.ba-horb.de 9019d90b1e Please enter the commit message for your changes. Lines starting
with '#' will be ignored, and an empty message aborts the commit.
2023-07-03 11:53:15 +02:00
dholle d07b2bdf0a Merge branch 'targetBytecode' of ssh://gohorb.ba-horb.de:/bahome/projekt/git/JavaCompilerCore into targetBytecode 2023-07-03 10:13:59 +02:00
dholle d05054755c Fix bug 2023-07-03 10:13:01 +02:00
luca9913 1a89920430 Created AST node TypePattern and adapted test cases in TestNewFeatures 2023-06-28 22:52:18 +02:00
luca9913 54a836b734 Added missing version to pom.xml 2023-06-28 22:12:28 +02:00
luca9913 8b3b07e32c Added test case Record(.jav) in TestNewFeatures 2023-06-28 22:10:08 +02:00
dholle d55b402269 Some fixes 2023-06-28 14:09:24 +02:00
luca9913 24900b8fcc Added test case for instanceof in syntaxtreegenerator 2023-06-27 20:25:31 +02:00
luca9913 2368a087c0 Added BoolExpression and instanceof to AST 2023-06-27 20:25:05 +02:00
luca9913 994a1571b7 Changed resources path in TestCodegen after merge 2023-06-27 19:14:28 +02:00
luca9913 aed1d3848b Resolved last merge conflict 2023-06-27 18:48:18 +02:00
luca9913 93cf39cfe9 Merge branch 'bigRefactoring' into patternMatching 2023-06-27 18:46:57 +02:00
dholle bdaf578f86 Fix equality 2023-06-27 15:48:15 +02:00
dholle 6079e96efa Test more thoroughly and add a new infimum deletion strategy 2023-06-27 15:01:28 +02:00
luca9913 41d8e223ce Fixed wrong resources path in TestCodegen 2023-06-26 20:24:59 +02:00
163 changed files with 19004 additions and 1437 deletions
File diff suppressed because it is too large Load Diff
+3 -11
View File
@@ -54,12 +54,8 @@ http://maven.apache.org/maven-v4_0_0.xsd">
<version>3.11.0</version>
<configuration>
<compilerArgs>--enable-preview</compilerArgs>
<<<<<<< HEAD
<source>20</source>
<target>20</target>
=======
<release>20</release>
>>>>>>> patternMatching
<source>21</source>
<target>21</target>
</configuration>
</plugin>
<plugin>
@@ -89,6 +85,7 @@ http://maven.apache.org/maven-v4_0_0.xsd">
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.3.0</version>
<configuration>
<archive>
<manifest>
@@ -127,11 +124,6 @@ http://maven.apache.org/maven-v4_0_0.xsd">
</repository>
</repositories>
<properties>
<<<<<<< HEAD
<maven.compiler.source>20</maven.compiler.source>
<maven.compiler.target>20</maven.compiler.target>
=======
>>>>>>> patternMatching
<mainClass>de.dhbwstuttgart.core.ConsoleInterface</mainClass>
</properties>
<distributionManagement>
+22
View File
@@ -0,0 +1,22 @@
class Pair<U, T> {
U a;
T b;
Pair(U x, T y) {
a = x; b = y;
}
}
class Complex {
m(b) {
var c = b;
var d = c;
var e;
d = e;
var r1 = e;
var f = e;
var g;
f = g;
var r2 = g;
return new Pair<>(r1, r2);
}
}
+7
View File
@@ -0,0 +1,7 @@
public class InfReturn {
m(a) {
var ret;
a = ret;
return ret;
}
}
+8
View File
@@ -0,0 +1,8 @@
public class InfReturnII {
m(a, b) {
var ret;
a = ret;
b = ret;
return ret;
}
}
+7
View File
@@ -0,0 +1,7 @@
class InnerInf {
m(a, b) {
var i;
a = i;
b = i;
}
}
+2 -2
View File
@@ -1,4 +1,4 @@
/*
class Pair<T, U> {
T x;
U y;
@@ -17,7 +17,7 @@ class Pair<T, U> {
return y;
}
}
*/
public class Iteration {
id(x) {
+7
View File
@@ -0,0 +1,7 @@
import java.lang.Integer;
import java.lang.Double;
class Overloading {
m(x) { return x + x; }
m(x) { return x || x; }
}
@@ -0,0 +1,8 @@
class RecursionCond {
m(a, b, c) {
if (1 == 2) {
b = m(a, b);
c = m(a, b);
} else return a;
}
}
+9
View File
@@ -0,0 +1,9 @@
import java.lang.Boolean;
import java.lang.Integer;
public class Test {
fac = (x) -> {
if (x == 1) { return 1; }
return x * fac.apply(x - 1);
};
}
+19
View File
@@ -0,0 +1,19 @@
class Triple<U, T, S> {
U a;
T b;
S c;
Triple(U x, T y, S z) {
a = x; b = y; c = z;
}
U fst() { return a; }
T snd() { return b; }
S thrd() { return c; }
}
public class TripleTest {
m() {
return new Triple<>(m().thrd(), m().thrd(), m().thrd());
}
}
+12
View File
@@ -0,0 +1,12 @@
class Twice2 {
id1inst = new Id<>();
id1 = id1inst.id;
id2inst = new Id<>();
id2 = id2inst.id;
twice = id1.apply(id2);
}
class Id<T> {
id = (T x) -> x;
}
+13
View File
@@ -0,0 +1,13 @@
import java.lang.Integer;
public class Chain {
x = 5;
chain() {
return this;
}
m() {
return this.chain().chain().chain().x;
}
}
View File
+1 -1
View File
@@ -1,8 +1,8 @@
import java.lang.Integer;
import java.lang.Double;
import java.lang.String;
public class Fac {
getFac(n) {
var res = 1;
var i = 1;
@@ -1,3 +1,5 @@
import java.lang.String;
public class FieldTph2 {
a;
+14 -14
View File
@@ -4,20 +4,20 @@ import java.lang.Boolean;
class For{
Integer m(Integer x){
var c = x + 2;
// Boolean b = true;
// c = 5;
// c++;
// ++c;
// c--;
// --c;
// while(x<2){
// x = x +1;
// b = false;
// }
return c;
// for(int i = 0;i<10;i++) {
// x = x + 5;
// }
Boolean b = true;
c = 5;
c++;
++c;
c--;
--c;
while(x<2){
x = x +1;
b = false;
}
for(int i = 0; i<10; i++) {
x = x + 5;
}
return x;
}
// m2(Integer x){
@@ -0,0 +1,15 @@
import java.lang.Integer;
import java.util.function.Function;
public class FunctionalInterface {
Integer accept(Function<Integer, Integer> f) {
return f.apply(20);
}
Integer m() {
var v = accept(i -> {
return i * 10;
});
return v;
}
}
@@ -0,0 +1,9 @@
import java.lang.System;
import java.lang.String;
import java.io.PrintStream;
public class HelloWorld {
static hello() {
System.out.println("Hello World!");
}
}
@@ -0,0 +1,18 @@
import java.lang.Number;
import java.lang.Integer;
import java.lang.Double;
import java.lang.String;
public class InstanceOf {
main(n) {
if (n instanceof Integer i) {
takes(i);
return "Integer";
} else if (n instanceof Double d) {
takes(d);
return "Double";
}
}
takes(i) {} // Should be overloaded
}
@@ -0,0 +1,33 @@
import java.lang.Integer;
interface A {
void method1();
default method2() {
}
}
interface B {
void method3();
}
interface C {
Integer myInt();
}
class ClassX implements A {
}
record ClassY(Integer myInt) implements C {}
public class Interfaces implements A, B {
public void method1() {
}
public void method3() {
var intf = new Interfaces();
intf = new ClassX();
intf.method1();
C c = new ClassY(10);
c.myInt();
}
}
@@ -1,13 +1,16 @@
import java.lang.Runnable;
import java.lang.String;
import java.lang.System;
import java.io.PrintStream;
public class LamRunnable{
public class LambdaRunnable {
public LamRunnable(){
public LambdaRunnable(){
Runnable lam = () -> {System.out.println("lambda");};
Runnable lam = () -> {
System.out.println("Runnable is running");
};
lam.run();
}
}
@@ -0,0 +1,50 @@
import java.lang.Integer;
import java.lang.Number;
import java.lang.Float;
record Point(Number x, Number y) {}
public class OverloadPattern {
m(Point(Integer x, Integer y)) {
return x + y;
}
m(Point(Float x, Float y)) {
return x * y;
}
m(Integer x) {
return x;
}
}
/*
public class OverloadPattern {
Integer m$Point$_$java$lang$Integer$_$java$lang$Integer$_$(Point point) {
var x = point.x();
var y = point.y();
return x + y;
}
Float m$Point$_$java$lang$Float$_$java$lang$Float$_$(Point point) {
var x = point.x();
var y = point.y();
return x * y;
}
Number m(Point point) {
return switch(point) {
case Point(Integer x, Integer y) ->
m$Point$_$java$lang$Integer$_$java$lang$Integer$_$(point);
case Point(Float x, Float y) ->
m$Point$_$java$lang$Float$_$java$lang$Float$_$(point);
default -> throw new IllegalArgumentException();
}
}
Integer m(Integer x) {
return x;
}
}
*/
@@ -0,0 +1,22 @@
import java.lang.Integer;
record Rec(Integer a, Integer b) {}
/*public class Rec {
x; y;
Rec(Integer a, Integer b) {
x = a;
y = b;
}
}*/
public class RecordTest {
a = new Rec(10, 20);
b = new Rec(10, 20);
c = new Rec(20, 40);
doesEqual() { return a.equals(b); }
doesNotEqual() { return b.equals(c); }
hashCode() { return a.hashCode(); }
toString() { return a.toString(); }
}
+18
View File
@@ -0,0 +1,18 @@
import java.lang.Integer;
class Other {
static field = 20;
}
public class Static {
static i = 20;
static {
var x = 30;
i = x;
}
static m() {
return i + Other.field;
}
}
+17
View File
@@ -0,0 +1,17 @@
import java.lang.Integer;
import java.lang.Object;
import java.lang.Float;
record Rec(Integer a, Object b) {}
public class Switch {
main(o) {
return switch (o) {
case Rec(Integer a, Integer b) -> a + b;
case Rec(Integer a, Float b) -> a + 10;
case Rec(Integer a, Rec(Integer b, Integer c)) -> a + b + c;
case Integer i -> i;
default -> 0;
};
}
}
+13
View File
@@ -0,0 +1,13 @@
import java.lang.Integer;
record Point(x, y) {}
class Switch2 {
m() {
var pt = new Point(10, 20);
return switch (pt) {
case Point(x, y) -> 10;
default -> 20;
};
}
}
@@ -0,0 +1,14 @@
import java.lang.Integer;
import java.lang.String;
import java.lang.Object;
public class SwitchString {
main(o) {
return switch (o) {
case "AaAaAa" -> 1; // These two have the same hash code!
case "AaAaBB" -> 2;
case "test", "TEST" -> 3;
default -> 4;
};
}
}
-12
View File
@@ -3,16 +3,4 @@ public class Tph2 {
id3 (x) {
return id.apply(x);
}
/*
m(a,b){
var c = m2(a,b);
//m2(a,b);
return a;
}
m2(a,b){
return b;
}
*/
}
View File
View File
View File
View File
View File
View File
+11
View File
@@ -0,0 +1,11 @@
package pkg.sub;
import java.lang.Integer;
import pkg.sub2.Cycle2;
public class Cycle1 {
test() {
var cycle2 = new Cycle2();
cycle2.test();
}
}
+11
View File
@@ -0,0 +1,11 @@
package pkg.sub;
import pkg.sub2.Test2;
public class Test1 {
main() {
var t2 = new Test2();
t2.test();
}
}
+11
View File
@@ -0,0 +1,11 @@
package pkg.sub2;
import java.lang.Integer;
import pkg.sub.Cycle1;
public class Cycle2 {
test() {
var cycle1 = new Cycle1();
cycle1.test();
}
}
+6
View File
@@ -0,0 +1,6 @@
package pkg.sub2;
public class Test2 {
test() {}
}
@@ -0,0 +1,44 @@
class Instanceof {
Instanceof(){
super(());
}
void checkInstanceof(){
TPH a;
a = 4;
return a instanceof java.lang.Integer;
}
void checkInstanceOfWithPattern(){
TPH b;
b = 4.0;
if(b instanceof d)
{
return d;
}
else
{
return Kein Double;
};
}
void checkInstanceOfWithGuardedPattern(){
TPH obj;
obj = test;
TPH flag;
if(obj instanceof s op s.length Signature: [TPH]() op 5)
{
flag = s.contains Signature: [TPH, TPH](jdk);
};
return;
}
java.lang.Boolean equals(java.lang.Object o){
return o instanceof other op x op other.x op y op other.y;
}
Instanceof(){
super(());
}
}
@@ -0,0 +1,120 @@
class Point {
java.lang.Integer x;
java.lang.Integer y;
Point(java.lang.Integer x, java.lang.Integer y){
super(());
this.x = x;
this.y = y;
}
java.lang.Integer x(){
return this.x;
}
java.lang.Integer y(){
return this.y;
}
Point(java.lang.Integer x, java.lang.Integer y){
super(());
this.x = x;
this.y = y;
}
}class Shape {
}class ColoredPoint {
Point pt;
java.lang.String color;
ColoredPoint(Point pt, java.lang.String color){
super(());
this.pt = pt;
this.color = color;
}
Point pt(){
return this.pt;
}
java.lang.String color(){
return this.color;
}
ColoredPoint(Point pt, java.lang.String color){
super(());
this.pt = pt;
this.color = color;
}
}class Rectangle {
ColoredPoint upperLeft;
ColoredPoint lowerRight;
Rectangle(ColoredPoint upperLeft, ColoredPoint lowerRight){
super(());
this.upperLeft = upperLeft;
this.lowerRight = lowerRight;
}
ColoredPoint upperLeft(){
return this.upperLeft;
}
ColoredPoint lowerRight(){
return this.lowerRight;
}
Rectangle(ColoredPoint upperLeft, ColoredPoint lowerRight){
super(());
this.upperLeft = upperLeft;
this.lowerRight = lowerRight;
}
}class Color {
Color(){
super(());
}
Color(){
super(());
}
}class Blue {
Blue(){
super(());
}
Blue(){
super(());
}
}class Red {
Red(){
super(());
}
Red(){
super(());
}
}class PatternMatching {
PatternMatching(){
super(());
}
void printColorOfUpperLeftPoint(Shape shape){
switch(shape){
case Rectangle(ColoredPoint(Point pt, java.lang.String color), ColoredPoint lowerRight):
System.out.println Signature: [TPH, TPH](x: op pt.x Signature: [TPH]() op / color: op color op / lowerRight: op lowerRight);
default:
System.out.println Signature: [TPH, TPH](not a rectangle);
};
return;
}
PatternMatching(){
super(());
}
}
+47
View File
@@ -0,0 +1,47 @@
class Point {
TPH x;
TPH y;
Point(TPH x, TPH y){
super(());
this.x = x;
this.y = y;
}
TPH x(){
return this.x;
}
TPH y(){
return this.y;
}
Point(TPH x, TPH y){
super(());
this.x = x;
this.y = y;
}
}class Line {
TPH pt1;
TPH pt2;
Line(TPH pt1, TPH pt2){
super(());
this.pt1 = pt1;
this.pt2 = pt2;
}
TPH pt1(){
return this.pt1;
}
TPH pt2(){
return this.pt2;
}
Line(TPH pt1, TPH pt2){
super(());
this.pt1 = pt1;
this.pt2 = pt2;
}
}
+144
View File
@@ -0,0 +1,144 @@
class Shape {
Shape(){
super(());
}
Shape(){
super(());
}
}class Circle {
Circle(){
super(());
}
Circle(){
super(());
}
}class Rectangle {
Rectangle(){
super(());
}
Rectangle(){
super(());
}
}class TransparentRectangle {
TransparentRectangle(){
super(());
}
TransparentRectangle(){
super(());
}
}class FilledRectangle {
FilledRectangle(){
super(());
}
FilledRectangle(){
super(());
}
}class Square {
Square(){
super(());
}
Square(){
super(());
}
}class WeirdShape {
WeirdShape(){
super(());
}
WeirdShape(){
super(());
}
}class Expr {
}class ConstantExpr {
java.lang.Integer i;
ConstantExpr(java.lang.Integer i){
super(());
this.i = i;
}
java.lang.Integer i(){
return this.i;
}
ConstantExpr(java.lang.Integer i){
super(());
this.i = i;
}
}class PlusExpr {
Expr a;
Expr b;
PlusExpr(Expr a, Expr b){
super(());
this.a = a;
this.b = b;
}
Expr a(){
return this.a;
}
Expr b(){
return this.b;
}
PlusExpr(Expr a, Expr b){
super(());
this.a = a;
this.b = b;
}
}class TimesExpr {
Expr a;
Expr b;
TimesExpr(Expr a, Expr b){
super(());
this.a = a;
this.b = b;
}
Expr a(){
return this.a;
}
Expr b(){
return this.b;
}
TimesExpr(Expr a, Expr b){
super(());
this.a = a;
this.b = b;
}
}class NegExpr {
Expr e;
NegExpr(Expr e){
super(());
this.e = e;
}
Expr e(){
return this.e;
}
NegExpr(Expr e){
super(());
this.e = e;
}
}
+96
View File
@@ -0,0 +1,96 @@
class SwitchStatement {
SwitchStatement(){
super(());
}
TPH switchStandard(){
str = SwitchMe;
switch(str){
case java.lang.String s:
return true;
default:
return false;
};
}
TPH switchInteger(){
i = 5;
switch(i){
case java.lang.Integer j:
case java.lang.String s:
i = 6;
break;
default:
i = 0;
break;
};
return i op 0;
}
TPH guardedPattern(){
TPH i;
i = 1;
switch(i){
case java.lang.Integer j:
return true;
default:
return false;
};
}
TPH recordPattern(java.lang.Object obj){
switch(obj){
case Coordinates(java.lang.Double lat, java.lang.Double lon):
return true;
default:
return false;
};
}
SwitchStatement(){
super(());
}
}class SwitchExpression {
java.lang.Integer x;
java.lang.Integer y;
SwitchExpression(java.lang.Integer x, java.lang.Integer y){
super(());
this.x = x;
this.y = y;
}
java.lang.Integer x(){
return this.x;
}
java.lang.Integer y(){
return this.y;
}
java.lang.Boolean switchStandard(TPH str){
return switch(str){
case java.lang.String s:
yield true;
default:
yield false;
};
}
SwitchExpression(java.lang.Integer x, java.lang.Integer y){
super(());
this.x = x;
this.y = y;
}
}
@@ -0,0 +1,36 @@
import java.lang.Integer;
import java.lang.Double;
import java.lang.String;
import java.lang.Object;
public class Instanceof{
void checkInstanceof() {
var a = 4;
return (a instanceof java.lang.Integer);
}
void checkInstanceOfWithPattern(){
var b = 4.0;
if(b instanceof java.lang.Double d){
return d;
}else{
return "Kein Double";
}
}
void checkInstanceOfWithGuardedPattern(){
var obj = "test";
var flag;
if (obj instanceof String s && s.length() > 5) {
flag = s.contains("jdk");
}
}
record Point(int x, int y){ }
boolean equals(Object o) {
return (o instanceof Point other)
&& x == other.x
&& y == other.y;
}
}
@@ -0,0 +1,19 @@
import java.lang.String;
record Point(int x, int y) {}
interface Shape {}
record ColoredPoint(Point pt, String color) {}
record Rectangle(ColoredPoint upperLeft, ColoredPoint lowerRight) implements Shape {}
sealed class Color permits Blue, Red {}
class Blue extends Color {}
class Red extends Color {}
class PatternMatching {
void printColorOfUpperLeftPoint(Shape shape)
{
switch (shape) {
case Rectangle(ColoredPoint(Point pt, String color), ColoredPoint lowerRight) -> System.out.println("x: " + pt.x() + " / color: " + color + " / lowerRight: " + lowerRight);
default -> System.out.println("not a rectangle");
};
}
}
@@ -0,0 +1,5 @@
// Simple records
record Point(x, y){ }
//Combination of records
record Line(pt1, pt2){}
@@ -0,0 +1,21 @@
public abstract sealed class Shape
permits Circle, Rectangle, Square, WeirdShape { }
public final class Circle extends Shape { }
public sealed class Rectangle extends Shape
permits TransparentRectangle, FilledRectangle { }
public final class TransparentRectangle extends Rectangle { }
public final class FilledRectangle extends Rectangle { }
public final class Square extends Shape { }
public non-sealed class WeirdShape extends Shape { }
public sealed interface Expr
permits ConstantExpr, PlusExpr, TimesExpr, NegExpr { }
public record ConstantExpr(int i) implements Expr { }
public record PlusExpr(Expr a, Expr b) implements Expr { }
public record TimesExpr(Expr a, Expr b) implements Expr { }
public record NegExpr(Expr e) implements Expr { }
@@ -0,0 +1,52 @@
import java.lang.Integer;
import java.lang.Boolean;
import java.lang.String;
import java.lang.Object;
class SwitchStatement {
switchStandard(){
str = "SwitchMe";
switch(str){
case String s: return true;
default: return false;
}
}
switchInteger(){
i = 5;
switch(i){
case Integer j:
case String s: i = 6; break;
default: i = 0; break;
}
return (i==0);
}
guardedPattern(){
var i = 1;
switch(i){
case Integer j && j == 1: return true;
default: return false;
}
}
record Coordinates(double x, double y) {}
recordPattern(Object obj){
switch(obj){
case Coordinates(double lat, double lon): return true;
default: return false;
}
}
}
record SwitchExpression(int x, int y){
boolean switchStandard(str){
return switch(str){
case String s -> yield true;
default -> yield false;
};
}
}
@@ -165,7 +165,7 @@ methodBody
;
refType
: typeType # reftype
: typeType # refType2
| VOID # refvoid
;
@@ -199,11 +199,7 @@ interfaceMemberDeclaration
: constDeclaration # interfaceconst
| interfaceMethodDeclaration # interfacemethod
| genericInterfaceMethodDeclaration # genericinterfacemethod
| interfaceDeclaration # subinterface
| annotationTypeDeclaration # interfaceannotationtype
| classDeclaration # interfaceclass
| enumDeclaration # interfaceenum
| recordDeclaration # interfacerecord // Java17
| classOrInterface # subclassorinterface
;
constDeclaration
@@ -308,6 +304,7 @@ formalParameterList
formalParameter
: variableModifier* typeType? variableDeclaratorId
| pattern // Pattern matching for Methods
;
lastFormalParameter
@@ -391,11 +388,7 @@ annotationTypeElementDeclaration
annotationTypeElementRest
: typeType annotationMethodOrConstantRest ';'
| classDeclaration ';'?
| interfaceDeclaration ';'?
| enumDeclaration ';'?
| annotationTypeDeclaration ';'?
| recordDeclaration ';'? // Java17
| classOrInterface ';'?
;
annotationMethodOrConstantRest
@@ -538,7 +531,6 @@ statement
| YIELD expression ';' #yieldstmt // Java17
| SEMI #semistmt
| statementExpression=expression ';' #stmtexpression
| switchExpression ';'? #switchexpressionstmt // Java17
| identifierLabel=identifier ':' statement #labeledstmt
;
@@ -575,8 +567,10 @@ switchBlockStatementGroup
;
switchLabel
: CASE (constantExpression=expression | enumConstantName=IDENTIFIER | pattern) ':'
| DEFAULT ':'
: CASE constantExpression=expression ':' #switchLabelConst
| CASE enumConstantName=IDENTIFIER ':' #switchLabelEnum
| CASE pattern ':' #switchLabelPattern
| DEFAULT ':' #switchLabelDefault
;
forControl
@@ -610,7 +604,7 @@ methodCall
;
expression
: primary #primaryexpression
: primary #primaryExpression2
| expression bop='.'
(
identifier
@@ -641,8 +635,8 @@ expression
| <assoc=right> expression
bop=('=' | '+=' | '-=' | '*=' | '/=' | '&=' | '|=' | '^=' | '>>=' | '>>>=' | '<<=' | '%=')
expression #assignexpression
| lambdaExpression #lambdaexpression // Java8
| switchExpression #switchexpression // Java17
| lambdaExpression #lambdaExpression2 // Java8
| switchExpression #switchExpression2 // Java17
// Java 8 methodReference
| expression '::' typeArguments? identifier #methodreferenceexpression
@@ -652,14 +646,14 @@ expression
// Java17
pattern
: primaryPattern
| guardedPattern
: primaryPattern #pPattern
| guardedPattern #gPattern
;
primaryPattern
: typePattern
| recordPattern
| '(' pattern ')'
: typePattern #tPattern
| recordPattern #rPattern
| '(' pattern ')' #enclosedPattern
;
recordPattern
@@ -667,13 +661,18 @@ recordPattern
;
typePattern
: variableModifier* typeType? identifier
: variableModifier* typeType identifier
;
recordStructurePattern
: '(' recordComponentPatternList? ')'
;
recordComponentPatternElement
: pattern
| identifier
;
recordComponentPatternList
: pattern (',' pattern)*
;
@@ -714,20 +713,25 @@ switchExpression
// Java17
switchLabeledRule
: CASE (expressionList | NULL_LITERAL | pattern) (ARROW | COLON) switchRuleOutcome
| DEFAULT (ARROW | COLON) switchRuleOutcome
: switchLabelCase switchRuleOutcome
;
// Java17
switchLabelCase
: CASE expressionList (ARROW | COLON) #labeledRuleExprList
| CASE NULL_LITERAL (ARROW | COLON) #labeledRuleNull
| CASE pattern (ARROW | COLON) #labeledRulePattern
| DEFAULT (ARROW | COLON) #labeledRuleDefault
;
// Java20
guardedPattern
: variableModifier* typeType? annotation* identifier ('&&' expression)*
| guardedPattern '&&' expression
: primaryPattern WITH expression
;
// Java17
switchRuleOutcome
: block
| blockStatement*
| expression ';'
;
classType
@@ -1,14 +1,17 @@
package de.dhbwstuttgart.bytecode;
import de.dhbwstuttgart.core.JavaTXCompiler;
import de.dhbwstuttgart.exceptions.NotImplementedException;
import de.dhbwstuttgart.parser.scope.JavaClassName;
import de.dhbwstuttgart.syntaxtree.ClassOrInterface;
import de.dhbwstuttgart.syntaxtree.type.RefType;
import de.dhbwstuttgart.target.tree.*;
import de.dhbwstuttgart.target.tree.expression.*;
import de.dhbwstuttgart.target.tree.type.*;
import org.objectweb.asm.*;
import java.lang.invoke.CallSite;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.invoke.*;
import java.lang.reflect.Modifier;
import java.util.*;
import static org.objectweb.asm.Opcodes.*;
@@ -16,16 +19,23 @@ import static de.dhbwstuttgart.target.tree.expression.TargetBinaryOp.*;
import static de.dhbwstuttgart.target.tree.expression.TargetLiteral.*;
public class Codegen {
private final TargetClass clazz;
private final TargetStructure clazz;
private final ClassWriter cw;
public final String className;
private int lambdaCounter = 0;
private final HashMap<TargetLambdaExpression, TargetMethod> lambdas = new HashMap<>();
private final JavaTXCompiler compiler;
public Codegen(TargetClass clazz) {
public Codegen(TargetStructure clazz, JavaTXCompiler compiler) {
this.clazz = clazz;
this.className = clazz.qualifiedName();
this.cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
this.className = clazz.qualifiedName().getClassName();
this.cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS) {
@Override
protected ClassLoader getClassLoader() {
return compiler.getClassLoader();
}
};
this.compiler = compiler;
}
private record LocalVar(int index, String name, TargetType type) {
@@ -55,11 +65,22 @@ public class Codegen {
}
}
private static class BreakEnv {
String labelName; // TODO This is for labeled statements (Not implemented)
Label startLabel;
Label endLabel;
}
private static class State {
Scope scope = new Scope(null);
int localCounter;
MethodVisitor mv;
TargetType returnType;
// This is used to remember the type from lambda expressions
TargetType contextType;
Stack<BreakEnv> breakStack = new Stack<>();
Stack<Integer> switchResultValue = new Stack<>();
State(TargetType returnType, MethodVisitor mv, int localCounter) {
this.returnType = returnType;
@@ -81,6 +102,13 @@ public class Codegen {
localCounter += 1;
return local;
}
void pushSwitch() {
switchResultValue.push(this.localCounter++);
}
void popSwitch() {
switchResultValue.pop();
}
}
private void popValue(State state, TargetType type) {
@@ -282,7 +310,7 @@ public class Codegen {
} else if (type.equals(TargetType.Double)) {
mv.visitInsn(DADD);
} else {
throw new CodeGenException("Invalid argument to Add expression");
throw new CodeGenException("Invalid argument to Add expression, type: " + add.type());
}
}
if (add.type().equals(TargetType.String)) {
@@ -432,6 +460,10 @@ public class Codegen {
mv.visitInsn(IXOR);
break;
}
case Instof instof: {
// TODO
throw new NotImplementedException();
}
case Shl shl: {
generate(state, shl.left());
convertTo(state, shl.left().type(), op.type());
@@ -547,6 +579,9 @@ public class Codegen {
}
break;
}
default: {
throw new NotImplementedException();
}
}
}
@@ -564,11 +599,10 @@ public class Codegen {
private void generateUnaryOp(State state, TargetUnaryOp op) {
var mv = state.mv;
switch (op) {
case TargetUnaryOp.Add add:
case TargetUnaryOp.Add add ->
// This literally does nothing
generate(state, add.expr());
break;
case TargetUnaryOp.Negate negate:
case TargetUnaryOp.Negate negate -> {
generate(state, negate.expr());
if (negate.type().equals(TargetType.Double))
mv.visitInsn(DNEG);
@@ -578,8 +612,8 @@ public class Codegen {
mv.visitInsn(LNEG);
else
mv.visitInsn(INEG);
break;
case TargetUnaryOp.Not not:
}
case TargetUnaryOp.Not not -> {
generate(state, not.expr());
if (not.type().equals(TargetType.Long)) {
mv.visitLdcInsn(-1L);
@@ -588,8 +622,8 @@ public class Codegen {
mv.visitInsn(ICONST_M1);
mv.visitInsn(IXOR);
}
break;
case TargetUnaryOp.PreIncrement preIncrement:
}
case TargetUnaryOp.PreIncrement preIncrement -> {
generate(state, preIncrement.expr());
if (preIncrement.type().equals(TargetType.Float)) {
mv.visitLdcInsn(1F);
@@ -610,8 +644,8 @@ public class Codegen {
}
boxPrimitive(state, preIncrement.type());
afterIncDec(state, preIncrement);
break;
case TargetUnaryOp.PreDecrement preDecrement:
}
case TargetUnaryOp.PreDecrement preDecrement -> {
generate(state, preDecrement.expr());
if (preDecrement.type().equals(TargetType.Float)) {
mv.visitLdcInsn(1F);
@@ -632,8 +666,8 @@ public class Codegen {
}
boxPrimitive(state, preDecrement.type());
afterIncDec(state, preDecrement);
break;
case TargetUnaryOp.PostIncrement postIncrement:
}
case TargetUnaryOp.PostIncrement postIncrement -> {
generate(state, postIncrement.expr());
if (postIncrement.type().equals(TargetType.Float)) {
mv.visitInsn(DUP);
@@ -654,8 +688,8 @@ public class Codegen {
}
boxPrimitive(state, postIncrement.type());
afterIncDec(state, postIncrement);
break;
case TargetUnaryOp.PostDecrement postDecrement:
}
case TargetUnaryOp.PostDecrement postDecrement -> {
generate(state, postDecrement.expr());
if (postDecrement.type().equals(TargetType.Float)) {
mv.visitInsn(DUP);
@@ -676,7 +710,7 @@ public class Codegen {
}
boxPrimitive(state, postDecrement.type());
afterIncDec(state, postDecrement);
break;
}
}
}
@@ -689,7 +723,7 @@ public class Codegen {
} else {
var name = "lambda$" + lambdaCounter++;
var parameters = new ArrayList<>(lambda.captures());
parameters.addAll(lambda.params().stream().map(param -> param.type() instanceof TargetGenericType ? new MethodParameter(TargetType.Object, param.name()) : param).toList());
parameters.addAll(lambda.params().stream().map(param -> param.pattern().type() instanceof TargetGenericType ? param.withType(TargetType.Object) : param).toList());
impl = new TargetMethod(0, name, lambda.block(), new TargetMethod.Signature(Set.of(), parameters, lambda.returnType() instanceof TargetGenericType ? TargetType.Object : lambda.returnType()), null);
generateMethod(impl);
@@ -712,15 +746,22 @@ public class Codegen {
desugared += "V";
var params = new ArrayList<TargetType>();
params.add(new TargetRefType(clazz.qualifiedName()));
params.addAll(lambda.captures().stream().map(MethodParameter::type).toList());
params.add(new TargetRefType(clazz.qualifiedName().getClassName()));
params.addAll(lambda.captures().stream().map(mp -> mp.pattern().type()).toList());
var descriptor = TargetMethod.getDescriptor(lambda.type(), params.toArray(TargetType[]::new));
var descriptor = TargetMethod.getDescriptor(state.contextType, params.toArray(TargetType[]::new));
mv.visitVarInsn(ALOAD, 0);
for (var capture : lambda.captures())
mv.visitVarInsn(ALOAD, state.scope.get(capture.name()).index);
for (var capture : lambda.captures()) {
var pattern = (TargetTypePattern) capture.pattern();
mv.visitVarInsn(ALOAD, state.scope.get(pattern.name()).index);
}
mv.visitInvokeDynamicInsn("apply", descriptor, bootstrap, Type.getType(desugared), handle, Type.getType(TargetMethod.getDescriptor(impl.signature().returnType(), lambda.params().stream().map(MethodParameter::type).toArray(TargetType[]::new))));
String methodName;
var intf = compiler.getClass(new JavaClassName(state.contextType.name()));
if (intf == null) methodName = "apply"; // TODO Weird fallback logic here
else methodName = intf.getMethods().stream().filter(m -> Modifier.isAbstract(m.modifier)).findFirst().orElseThrow().getName();
mv.visitInvokeDynamicInsn(methodName, descriptor, bootstrap, Type.getType(desugared), handle, Type.getType(TargetMethod.getDescriptor(impl.signature().returnType(), lambda.params().stream().map(mp -> mp.pattern().type()).toArray(TargetType[]::new))));
}
private void generate(State state, TargetExpression expr) {
@@ -747,39 +788,30 @@ public class Codegen {
break;
}
case TargetCast cast:
var ctx = state.contextType;
state.contextType = cast.type();
generate(state, cast.expr());
state.contextType = ctx;
convertTo(state, cast.expr().type(), cast.type());
break;
case TargetInstanceOf instanceOf:
mv.visitTypeInsn(INSTANCEOF, instanceOf.right().getInternalName());
generateInstanceOf(state, instanceOf);
break;
case TargetLiteral literal:
switch (literal) {
case IntLiteral intLiteral:
mv.visitLdcInsn(intLiteral.value());
break;
case FloatLiteral floatLiteral:
mv.visitLdcInsn(floatLiteral.value());
break;
case LongLiteral longLiteral:
mv.visitLdcInsn(longLiteral.value());
break;
case StringLiteral stringLiteral:
mv.visitLdcInsn(stringLiteral.value());
break;
case CharLiteral charLiteral:
mv.visitIntInsn(BIPUSH, charLiteral.value());
break;
case DoubleLiteral doubleLiteral:
mv.visitLdcInsn(doubleLiteral.value());
break;
case BooleanLiteral booleanLiteral:
case IntLiteral intLiteral -> mv.visitLdcInsn(intLiteral.value());
case FloatLiteral floatLiteral -> mv.visitLdcInsn(floatLiteral.value());
case LongLiteral longLiteral -> mv.visitLdcInsn(longLiteral.value());
case StringLiteral stringLiteral -> mv.visitLdcInsn(stringLiteral.value());
case CharLiteral charLiteral -> mv.visitIntInsn(BIPUSH, charLiteral.value());
case DoubleLiteral doubleLiteral -> mv.visitLdcInsn(doubleLiteral.value());
case BooleanLiteral booleanLiteral -> {
if (booleanLiteral.value()) {
mv.visitInsn(ICONST_1);
} else {
mv.visitInsn(ICONST_0);
}
break;
}
}
break;
case TargetVarDecl varDecl: {
@@ -802,19 +834,28 @@ public class Codegen {
break;
case TargetAssign assign: {
switch (assign.left()) {
case TargetLocalVar localVar: {
case TargetLocalVar localVar -> {
var ctype = state.contextType;
state.contextType = localVar.type();
generate(state, assign.right());
state.contextType = ctype;
convertTo(state, assign.right().type(), localVar.type());
boxPrimitive(state, localVar.type());
var local = state.scope.get(localVar.name());
mv.visitInsn(DUP);
mv.visitVarInsn(ASTORE, local.index());
break;
}
case TargetFieldVar dot: {
case TargetFieldVar dot -> {
var fieldType = dot.type();
if (!(dot.left() instanceof TargetThis && dot.isStatic()))
generate(state, dot.left());
var ctype = state.contextType;
state.contextType = fieldType;
generate(state, assign.right());
state.contextType = ctype;
convertTo(state, assign.right().type(), fieldType);
boxPrimitive(state, fieldType);
if (dot.isStatic())
@@ -822,10 +863,8 @@ public class Codegen {
else
mv.visitInsn(DUP_X1);
mv.visitFieldInsn(dot.isStatic() ? PUTSTATIC : PUTFIELD, dot.owner().getInternalName(), dot.right(), fieldType.toSignature());
break;
}
default:
throw new CodeGenException("Invalid assignment");
default -> throw new CodeGenException("Invalid assignment");
}
break;
}
@@ -846,7 +885,8 @@ public class Codegen {
state.enterScope();
var localCounter = state.localCounter;
if (_for.init() != null)
generate(state, _for.init());
_for.init().forEach(e -> generate(state, e));
Label start = new Label();
Label end = new Label();
mv.visitLabel(start);
@@ -855,12 +895,22 @@ public class Codegen {
else
mv.visitInsn(ICONST_1);
mv.visitJumpInsn(IFEQ, end);
var env = new BreakEnv();
env.startLabel = start;
env.endLabel = end;
state.breakStack.push(env);
generate(state, _for.body());
state.breakStack.pop();
if (_for.increment() != null) {
generate(state, _for.increment());
if (_for.increment().type() != null) {
popValue(state, _for.increment().type());
_for.increment().forEach(e -> {
generate(state, e);
if (e.type() != null) {
popValue(state, e.type());
}
});
}
mv.visitJumpInsn(GOTO, start);
mv.visitLabel(end);
@@ -874,7 +924,15 @@ public class Codegen {
mv.visitLabel(start);
generate(state, _while.cond());
mv.visitJumpInsn(IFEQ, end);
var env = new BreakEnv();
env.startLabel = start;
env.endLabel = end;
state.breakStack.push(env);
generate(state, _while.body());
state.breakStack.pop();
mv.visitJumpInsn(GOTO, start);
mv.visitLabel(end);
break;
@@ -895,7 +953,10 @@ public class Codegen {
}
case TargetReturn ret: {
if (ret.expression() != null && state.returnType != null) {
var ctype = state.contextType;
state.contextType = state.returnType;
generate(state, ret.expression());
state.contextType = ctype;
convertTo(state, ret.expression().type(), state.returnType);
boxPrimitive(state, state.returnType);
mv.visitInsn(ARETURN);
@@ -903,6 +964,32 @@ public class Codegen {
mv.visitInsn(RETURN);
break;
}
case TargetYield yield: {
generate(state, yield.expression());
try {
yieldValue(state, yield.expression().type());
mv.visitJumpInsn(GOTO, state.breakStack.peek().endLabel);
} catch (EmptyStackException e) {
throw new CodeGenException("Yield outside of switch expression");
}
break;
}
case TargetSwitch _switch: {
generateSwitch(state, _switch);
break;
}
case TargetBreak brk: {
if (state.breakStack.isEmpty()) throw new CodeGenException("Break outside of switch or loop");
mv.visitJumpInsn(GOTO, state.breakStack.peek().endLabel);
break;
}
case TargetContinue cnt: {
if (state.breakStack.isEmpty()) throw new CodeGenException("Continue outside of loop");
var env = state.breakStack.peek();
if (env.startLabel == null) throw new CodeGenException("Continue outside of loop");
mv.visitJumpInsn(GOTO, env.startLabel);
break;
}
case TargetThis _this: {
mv.visitVarInsn(ALOAD, 0);
break;
@@ -916,9 +1003,12 @@ public class Codegen {
for (var i = 0; i < call.args().size(); i++) {
var e = call.args().get(i);
var arg = call.parameterTypes().get(i);
var ctype = state.contextType;
state.contextType = arg;
generate(state, e);
if (!(arg instanceof TargetPrimitiveType))
boxPrimitive(state, e.type());
state.contextType = ctype;
}
var descriptor = call.getDescriptor();
if (call.owner() instanceof TargetFunNType) // Decay FunN
@@ -951,8 +1041,294 @@ public class Codegen {
}
}
private void generateInstanceOf(State state, TargetInstanceOf instanceOf) {
var mv = state.mv;
if (instanceOf.right() instanceof TargetTypePattern right && right.name() == null) {
mv.visitTypeInsn(INSTANCEOF, right.type().getInternalName());
return;
}
throw new NotImplementedException();
}
private void yieldValue(State state, TargetType type) {
boxPrimitive(state, type);
state.mv.visitVarInsn(ASTORE, state.switchResultValue.peek());
}
private void generateClassicSwitch(State state, TargetSwitch aSwitch) {
// TODO Constant expressions are allowed, we need to evaluate them somehow...
// For now we just assume we get literals...
// TODO This always uses a lookupswitch, a tableswitch may be faster in some cases but we can't generate that every time
// TODO We can't switch on Strings yet, the idea for this (like javac does it) would be to implement the hash code at compile time
// and switch based on that, adding an equals check for every case and going to yet another tableswitch which finally decides which branch to take
var mv = state.mv;
if (aSwitch.isExpression())
state.pushSwitch();
generate(state, aSwitch.expr());
state.enterScope();
var keys = new int[aSwitch.cases().stream().mapToInt(c -> c.labels().size()).sum()];
var labels = new Label[keys.length];
var bodyLabels = new Label[aSwitch.cases().size()];
var end = new Label();
var env = new BreakEnv();
env.endLabel = end;
state.breakStack.push(env);
var i = 0;
var j = 0;
for (var case_ : aSwitch.cases()) {
bodyLabels[j] = new Label();
for (var label : case_.labels()) {
if (!(label instanceof TargetLiteral literal))
throw new CodeGenException("Labels may only be constants for now");
keys[i] = (int) literal.value();
labels[i] = bodyLabels[j];
i += 1;
}
j += 1;
}
var defaultLabel = end;
if (aSwitch.default_() != null) {
defaultLabel = new Label();
}
mv.visitLookupSwitchInsn(defaultLabel, keys, labels);
for (var k = 0; k < aSwitch.cases().size(); k++) {
mv.visitLabel(bodyLabels[k]);
var cse = aSwitch.cases().get(k);
generate(state, cse.body());
if (cse.isSingleExpression() && aSwitch.isExpression())
yieldValue(state, cse.body().statements().get(0).type());
if (aSwitch.isExpression()) mv.visitJumpInsn(GOTO, end);
}
if (aSwitch.default_() != null) {
mv.visitLabel(defaultLabel);
generate(state, aSwitch.default_().body());
if (aSwitch.default_().isSingleExpression() && aSwitch.isExpression())
yieldValue(state, aSwitch.default_().body().statements().get(0).type());
}
mv.visitLabel(end);
state.breakStack.pop();
if (aSwitch.isExpression()) {
mv.visitVarInsn(ALOAD, state.switchResultValue.peek());
unboxPrimitive(state, aSwitch.type());
state.popSwitch();
}
state.exitScope();
}
private void generateEnhancedSwitch(State state, TargetSwitch aSwitch) {
var mv = state.mv;
generate(state, aSwitch.expr());
var tmp = state.localCounter;
mv.visitInsn(DUP);
mv.visitVarInsn(ASTORE, tmp);
state.enterScope();
// This is the index to start the switch from
mv.visitInsn(ICONST_0);
if (aSwitch.isExpression())
state.pushSwitch();
// To be able to skip ahead to the next case
var start = new Label();
mv.visitLabel(start);
var end = new Label();
var env = new BreakEnv();
env.endLabel = end;
state.breakStack.push(env);
var mt = MethodType.methodType(CallSite.class, MethodHandles.Lookup.class, String.class, MethodType.class, Object[].class);
var bootstrap = new Handle(H_INVOKESTATIC, "java/lang/runtime/SwitchBootstraps", "typeSwitch", mt.toMethodDescriptorString(), false);
var types = new ArrayList<Object>(aSwitch.cases().size());
for (var cse : aSwitch.cases()) for (var label : cse.labels()) {
if (label instanceof TargetTypePattern || label instanceof TargetComplexPattern)
types.add(Type.getObjectType(label.type().getInternalName()));
else if (label instanceof TargetLiteral lit)
types.add(lit.value());
else if (label instanceof TargetGuard guard)
types.add(Type.getObjectType(guard.inner().type().getInternalName()));
// TODO Same here we need to evaluate constant;
else {
System.out.println(label);
throw new NotImplementedException();
}
}
mv.visitInvokeDynamicInsn("typeSwitch", "(Ljava/lang/Object;I)I", bootstrap, types.toArray());
var caseLabels = new Label[aSwitch.cases().size()];
var labels = new Label[aSwitch.cases().stream().mapToInt(c -> c.labels().size()).sum()];
var j = 0;
for (var i = 0; i < caseLabels.length; i++) {
var cse = aSwitch.cases().get(i);
var label = new Label();
caseLabels[i] = label;
for (var k = 0; k < cse.labels().size(); k++) {
labels[j] = label;
j += 1;
}
}
var defaultLabel = end;
if (aSwitch.default_() != null) {
defaultLabel = new Label();
}
mv.visitTableSwitchInsn(0, labels.length - 1, defaultLabel, labels);
for (var i = 0; i < aSwitch.cases().size(); i++) {
mv.visitLabel(caseLabels[i]);
var cse = aSwitch.cases().get(i);
if (cse.labels().size() == 1) {
var label = cse.labels().get(0);
if (label instanceof TargetGuard gd) {
state.mv.visitVarInsn(ALOAD, tmp);
bindPattern(state, aSwitch.expr().type(), gd.inner(), start, i, 1);
} else if (label instanceof TargetPattern pat) {
state.mv.visitVarInsn(ALOAD, tmp);
bindPattern(state, aSwitch.expr().type(), pat, start, i, 1);
}
if (label instanceof TargetGuard gd) {
generate(state, gd.expression());
var next = new Label();
mv.visitJumpInsn(IFNE, next);
mv.visitVarInsn(ALOAD, tmp);
// Push the offset onto the stack (this is used by the invokedynamic call)
mv.visitLdcInsn(i + 1);
mv.visitJumpInsn(GOTO, start);
mv.visitLabel(next);
}
}
generate(state, cse.body());
if (cse.isSingleExpression() && aSwitch.isExpression())
yieldValue(state, cse.body().statements().get(0).type());
if (aSwitch.isExpression()) mv.visitJumpInsn(GOTO, end);
}
if (aSwitch.default_() != null) {
mv.visitLabel(defaultLabel);
generate(state, aSwitch.default_().body());
if (aSwitch.default_().isSingleExpression() && aSwitch.isExpression())
yieldValue(state, aSwitch.default_().body().statements().get(0).type());
}
mv.visitLabel(end);
//mv.visitInsn(POP);
state.breakStack.pop();
if (aSwitch.isExpression()) {
mv.visitVarInsn(ALOAD, state.switchResultValue.peek());
unboxPrimitive(state, aSwitch.type());
state.popSwitch();
}
state.exitScope();
}
private void extractField(State state, TargetType type, int i, ClassOrInterface clazz) {
if (i >= clazz.getFieldDecl().size())
throw new CodeGenException("Couldn't find suitable field accessor for '" + type.name() + "'");
var field = clazz.getFieldDecl().get(i);
var fieldType = new TargetRefType(((RefType) field.getType()).getName().toString());
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) {
if (pat.type() instanceof TargetPrimitiveType)
boxPrimitive(state, pat.type());
state.mv.visitInsn(DUP);
state.mv.visitTypeInsn(INSTANCEOF, pat.type().getInternalName());
var cont = new Label();
state.mv.visitJumpInsn(IFNE, cont);
for (var i = 0; i < depth; i++) {
state.mv.visitInsn(POP);
}
state.mv.visitVarInsn(ALOAD, state.switchResultValue.peek());
state.mv.visitLdcInsn(index + 1);
state.mv.visitJumpInsn(GOTO, start);
state.mv.visitLabel(cont);
state.mv.visitTypeInsn(CHECKCAST, pat.type().getInternalName());
if (pat instanceof TargetTypePattern sp) {
var local = state.createVariable(sp.name(), sp.type());
state.mv.visitVarInsn(ASTORE, local.index);
} else if (pat instanceof TargetComplexPattern cp) {
if (cp.name() != null) {
state.mv.visitInsn(DUP);
var local = state.createVariable(cp.name(), cp.type());
state.mv.visitVarInsn(ASTORE, local.index);
}
var clazz = findClass(new JavaClassName(cp.type().name()));
if (clazz == null) throw new CodeGenException("Class definition for '" + cp.type().name() + "' not found");
// TODO Check if class is a Record
for (var i = 0; i < cp.subPatterns().size(); i++) {
state.mv.visitInsn(DUP);
var subPattern = cp.subPatterns().get(i);
extractField(state, cp.type(), i, clazz);
bindPattern(state, subPattern.type(), subPattern, start, index, depth + 1);
}
state.mv.visitInsn(POP);
}
}
final Set<TargetType> wrapperTypes = Set.of(TargetType.Long, TargetType.Integer, TargetType.Byte, TargetType.Char, TargetType.Boolean, TargetType.Double, TargetType.Float);
private void generateSwitch(State state, TargetSwitch aSwitch) {
if (!wrapperTypes.contains(aSwitch.expr().type())) {
generateEnhancedSwitch(state, aSwitch);
return;
}
else for (var case_ : aSwitch.cases()) {
if (case_.labels().stream().anyMatch(c -> c instanceof TargetPattern)) {
generateEnhancedSwitch(state, aSwitch);
return;
}
}
generateClassicSwitch(state, aSwitch);
}
private void generateField(TargetField field) {
cw.visitField(field.access() | ACC_PUBLIC, field.name(), field.type().toSignature(), field.type().toDescriptor(), null);
var access = field.access();
if ((access & ACC_PRIVATE) == 0 && (access & ACC_PROTECTED) == 0) // TODO Implement access modifiers properly
access |= ACC_PUBLIC;
cw.visitField(access, field.name(), field.type().toSignature(), field.type().toDescriptor(), null);
}
private void generateStaticConstructor(TargetMethod constructor) {
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "<clinit>", "()V", null, null);
mv.visitCode();
var state = new State(null, mv, 0);
generate(state, constructor.block());
mv.visitInsn(RETURN);
mv.visitMaxs(0, 0);
mv.visitEnd();
}
private void generateConstructor(TargetConstructor constructor) {
@@ -962,8 +1338,12 @@ public class Codegen {
mv.visitCode();
var state = new State(null, mv, 1);
for (var param : constructor.parameters())
state.createVariable(param.name(), param.type());
for (var param : constructor.parameters()) {
var pattern = param.pattern();
if (pattern instanceof TargetTypePattern tp)
state.createVariable(tp.name(), tp.type());
else throw new NotImplementedException();
}
var stmts = constructor.block().statements();
generate(state, stmts.get(0));
@@ -981,48 +1361,160 @@ public class Codegen {
mv.visitEnd();
}
private int bindLocalVariables(State state, TargetPattern pattern, int offset, int field) {
if (pattern instanceof TargetComplexPattern cp) {
state.mv.visitVarInsn(ALOAD, offset);
var clazz = findClass(new JavaClassName(cp.type().name()));
if (clazz == null) throw new CodeGenException("Class definition for '" + cp.type().name() + "' not found");
for (var i = 0; i < cp.subPatterns().size(); i++) {
var subPattern = cp.subPatterns().get(i);
if (i < cp.subPatterns().size() - 1)
state.mv.visitInsn(DUP);
extractField(state, cp.type(), i, clazz);
state.mv.visitTypeInsn(CHECKCAST, subPattern.type().getInternalName());
state.mv.visitVarInsn(ASTORE, offset);
offset = bindLocalVariables(state, subPattern, offset, i);
}
} else if (pattern instanceof TargetTypePattern tp) {
offset++;
state.createVariable(tp.name(), tp.type());
} else throw new NotImplementedException();
return offset;
}
private void generateMethod(TargetMethod method) {
var access = method.access() | ACC_PUBLIC;
if (method.block() == null)
access |= ACC_ABSTRACT;
// TODO The older codegen has set ACC_PUBLIC for all methods, good for testing but bad for everything else
MethodVisitor mv = cw.visitMethod(method.access() | ACC_PUBLIC, method.name(), method.getDescriptor(), method.getSignature(), null);
MethodVisitor mv = cw.visitMethod(access, method.name(), method.getDescriptor(), method.getSignature(), null);
if (method.txSignature() != null) {
mv.visitAttribute(new JavaTXSignatureAttribute(method.getTXSignature()));
}
if (method.block() != null) {
mv.visitCode();
var state = new State(method.signature().returnType(), mv, method.isStatic() ? 0 : 1);
for (var param : method.signature().parameters())
state.createVariable(param.name(), param.type());
for (var param : method.signature().parameters()) {
bindLocalVariables(state, param.pattern(), 1, 0);
}
generate(state, method.block());
if (method.signature().returnType() == null)
mv.visitInsn(RETURN);
mv.visitMaxs(0, 0);
}
mv.visitEnd();
}
private static String generateSignature(TargetClass clazz, Set<TargetGeneric> generics) {
private static String generateSignature(TargetStructure clazz, Set<TargetGeneric> generics) {
String ret = "";
if (generics.size() > 0) {
if (!generics.isEmpty()) {
ret += "<";
for (var generic : generics) {
ret += generic.name() + ":" + generic.bound().toDescriptor();
}
ret += ">";
}
if (clazz.superType() != null)
ret += clazz.superType().toDescriptor();
for (var intf : clazz.implementingInterfaces()) {
ret += intf.toSignature();
}
return ret;
return ret.isEmpty() ? null : ret;
}
public byte[] generate() {
cw.visit(V1_8, clazz.modifiers() | ACC_PUBLIC | ACC_SUPER, clazz.qualifiedName(), generateSignature(clazz, clazz.generics()), clazz.superType() != null ? clazz.superType().getInternalName() : "java/lang/Object", clazz.implementingInterfaces().stream().map(TargetType::toSignature).toArray(String[]::new));
if (clazz.txGenerics() != null)
var access = clazz.modifiers();
if ((access & ACC_PRIVATE) == 0 && (access & ACC_PROTECTED) == 0) // TODO Implement access modifiers properly
access |= ACC_PUBLIC;
if (!(clazz instanceof TargetInterface))
access |= ACC_SUPER;
var signature = generateSignature(clazz, clazz.generics());
var interfaces = clazz.implementingInterfaces().stream().map(TargetType::getInternalName).toArray(String[]::new);
var superType = clazz.superType() != null ? clazz.superType().getInternalName() : "java/lang/Object";
cw.visit(V1_8, access, clazz.qualifiedName().toString().replaceAll("\\.", "/"), signature, superType, interfaces);
if (clazz.txGenerics() != null && signature != null)
cw.visitAttribute(new JavaTXSignatureAttribute(generateSignature(clazz, clazz.txGenerics())));
clazz.fields().forEach(this::generateField);
clazz.constructors().forEach(this::generateConstructor);
clazz.methods().forEach(this::generateMethod);
if (clazz.staticConstructor() != null)
generateStaticConstructor(clazz.staticConstructor());
if (clazz instanceof TargetRecord)
generateRecordMethods();
cw.visitEnd();
return cw.toByteArray();
}
private ClassOrInterface findClass(JavaClassName className) {
try {
for (var sf : compiler.sourceFiles.values()) {
for (var clazz : compiler.getAvailableClasses(sf)) {
if (clazz.getClassName().equals(className))
return clazz;
}
for (var clazz : sf.KlassenVektor) {
if (clazz.getClassName().equals(className))
return clazz;
}
}
} catch (ClassNotFoundException ignored) {}
return null;
}
private void generateRecordMethods() {
var mt = MethodType.methodType(Object.class, MethodHandles.Lookup.class, String.class, TypeDescriptor.class, Class.class, String.class, MethodHandle[].class);
var bootstrap = new Handle(H_INVOKESTATIC, "java/lang/runtime/ObjectMethods", "bootstrap", mt.toMethodDescriptorString(), false);
var bootstrapArgs = new Object[2 + clazz.fields().size()];
bootstrapArgs[0] = Type.getObjectType(clazz.getName());
bootstrapArgs[1] = String.join(";", clazz.fields().stream().map(TargetField::name).toArray(String[]::new));
for (var i = 0; i < clazz.fields().size(); i++) {
var field = clazz.fields().get(i);
var fieldRef = new Handle(H_GETFIELD, clazz.getName(), field.name(), field.type().toDescriptor(), false);
bootstrapArgs[i + 2] = fieldRef;
}
{ // hashCode
var mv = cw.visitMethod(ACC_PUBLIC, "hashCode", "()I", null, null);
mv.visitCode();
mv.visitVarInsn(ALOAD, 0);
mv.visitInvokeDynamicInsn("hashCode", "(L" + clazz.getName() + ";)I", bootstrap, bootstrapArgs);
mv.visitInsn(IRETURN);
mv.visitMaxs(0, 0);
mv.visitEnd();
}
{ // equals
var mv = cw.visitMethod(ACC_PUBLIC, "equals", "(Ljava/lang/Object;)Z", null, null);
mv.visitCode();
mv.visitVarInsn(ALOAD, 0);
mv.visitVarInsn(ALOAD, 1);
mv.visitInvokeDynamicInsn("equals", "(L" + clazz.getName() + ";Ljava/lang/Object;)Z", bootstrap, bootstrapArgs);
mv.visitInsn(IRETURN);
mv.visitMaxs(0, 0);
mv.visitEnd();
}
{ // toString
var mv = cw.visitMethod(ACC_PUBLIC, "toString", "()Ljava/lang/String;", null, null);
mv.visitCode();
mv.visitVarInsn(ALOAD, 0);
mv.visitInvokeDynamicInsn("toString", "(L" + clazz.getName() + ";)Ljava/lang/String;", bootstrap, bootstrapArgs);
mv.visitInsn(ARETURN);
mv.visitMaxs(0, 0);
mv.visitEnd();
}
}
}
@@ -28,12 +28,15 @@ public class FunNGenerator {
private static final String objectSuperType = Type.getInternalName(Object.class).replace('.','/');
private static final String objectSignature = applySignature(TargetType.Object);
private static final String VOID = "Ljava/lang/Void;";
public static class GenericParameters {
int start;
public List<TargetType> parameters = new ArrayList<>();
}
private static String applyDescriptor(TargetType type, GenericParameters gep) {
if (type == null) return VOID;
var res = "L" + type.getInternalName();
if (type instanceof TargetSpecializedType a) {
if (a.params().size() > 0) {
@@ -59,7 +62,12 @@ public class FunNGenerator {
}
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", applySignature(a)); }
public static String encodeType(TargetType type) {
if (type == null) return VOID;
return applyNameDescriptor(type).replace("/", "$").replace(";", "$_$");
}
public static byte[] generateSuperBytecode(int numberArguments) {
StringBuilder superFunNClassSignature = new StringBuilder("<");
@@ -130,11 +138,9 @@ public class FunNGenerator {
argumentTypes.size(),
argumentTypes
.stream()
.map(FunNGenerator::applyNameDescriptor)
.map(FunNGenerator::encodeType)
.collect(Collectors.joining()),
applyNameDescriptor(returnType))
.replace('/', '$')
.replace(";", "$_$");
encodeType(returnType));
}
public static List<TargetType> getArguments(List<TargetType> list) {
@@ -12,12 +12,12 @@ import de.dhbwstuttgart.parser.scope.GenericsRegistry;
import de.dhbwstuttgart.parser.SyntaxTreeGenerator.SyntaxTreeGenerator;
import de.dhbwstuttgart.parser.antlr.Java17Parser.SourceFileContext;
import de.dhbwstuttgart.parser.scope.JavaClassName;
import de.dhbwstuttgart.parser.scope.JavaClassRegistry;
import de.dhbwstuttgart.syntaxtree.ClassOrInterface;
import de.dhbwstuttgart.syntaxtree.GenericTypeVar;
import de.dhbwstuttgart.syntaxtree.Method;
import de.dhbwstuttgart.syntaxtree.ParameterList;
import de.dhbwstuttgart.syntaxtree.SourceFile;
import de.dhbwstuttgart.syntaxtree.FormalParameter;
import de.dhbwstuttgart.syntaxtree.GenericDeclarationList;
import de.dhbwstuttgart.syntaxtree.factory.ASTFactory;
import de.dhbwstuttgart.syntaxtree.factory.UnifyTypeFactory;
@@ -31,6 +31,7 @@ import de.dhbwstuttgart.syntaxtree.type.TypeVisitor;
import de.dhbwstuttgart.syntaxtree.visual.ASTTypePrinter;
import de.dhbwstuttgart.target.generate.ASTToTargetAST;
import de.dhbwstuttgart.target.generate.GenericsResult;
import de.dhbwstuttgart.target.tree.expression.TargetBinaryOp;
import de.dhbwstuttgart.typeinference.constraints.Constraint;
import de.dhbwstuttgart.typeinference.constraints.ConstraintSet;
import de.dhbwstuttgart.typeinference.constraints.Pair;
@@ -44,7 +45,6 @@ import de.dhbwstuttgart.typeinference.unify.model.PairOperator;
import de.dhbwstuttgart.typeinference.unify.model.PlaceholderType;
import de.dhbwstuttgart.typeinference.unify.model.UnifyPair;
import de.dhbwstuttgart.typeinference.unify.model.UnifyType;
import de.dhbwstuttgart.util.BiRelation;
import de.dhbwstuttgart.typeinference.unify.TypeUnifyTask;
import de.dhbwstuttgart.typeinference.unify.UnifyResultListener;
import de.dhbwstuttgart.typeinference.unify.UnifyResultListenerImpl;
@@ -62,7 +62,6 @@ import java.util.Map.Entry;
import java.util.function.Function;
import java.util.stream.Collectors;
import org.antlr.v4.runtime.Token;
import org.apache.commons.io.output.NullOutputStream;
public class JavaTXCompiler {
@@ -71,10 +70,17 @@ public class JavaTXCompiler {
final CompilationEnvironment environment;
Boolean resultmodel = false;
public final Map<File, SourceFile> sourceFiles = new HashMap<>();
Boolean log = false; // gibt an ob ein Log-File nach System.getProperty("user.dir")+""/logFiles/"" geschrieben werden soll?
Boolean log = true; //gibt an ob ein Log-File nach System.getProperty("user.dir")+""/logFiles/"" geschrieben werden soll?
public volatile UnifyTaskModel usedTasks = new UnifyTaskModel();
private final DirectoryClassLoader classLoader;
private final List<File> classPath;
public DirectoryClassLoader getClassLoader() {
return classLoader;
}
public JavaTXCompiler(File sourceFile) throws IOException, ClassNotFoundException {
this(Arrays.asList(sourceFile), null);
}
@@ -95,12 +101,32 @@ public class JavaTXCompiler {
}
classLoader = new DirectoryClassLoader(contextPath, ClassLoader.getSystemClassLoader());
environment = new CompilationEnvironment(sources);
classPath = contextPath;
for (File s : sources) {
sourceFiles.put(s, parse(s));
parse(s);
}
// INSTANCE = this;
}
private void addSourceFile(File file, SourceFile sf) {
sourceFiles.put(file, sf);
}
public ClassOrInterface getClass(JavaClassName name) {
for (var sf : sourceFiles.values()) {
for (var clazz : sf.KlassenVektor) {
if (clazz.getClassName().equals(name)) return clazz;
}
}
try {
var clazz = classLoader.loadClass(name.toString());
if (clazz != null)
return ASTFactory.createClass(clazz);
} catch (ClassNotFoundException ignored) {}
return null;
}
public ConstraintSet<Pair> getConstraints() throws ClassNotFoundException, IOException {
List<ClassOrInterface> allClasses = new ArrayList<>();// environment.getAllAvailableClasses();
List<ClassOrInterface> importedClasses = new ArrayList<>();
@@ -108,11 +134,9 @@ public class JavaTXCompiler {
// Alle Importierten Klassen in allen geparsten Sourcefiles kommen ins FC
for (Entry<File, SourceFile> source : sourceFiles.entrySet()) {
for (JavaClassName name : source.getValue().getImports()) {
// TODO: Hier werden imports von eigenen (.jav) Klassen nicht beachtet
ClassOrInterface importedClass = ASTFactory.createClass(classLoader.loadClass(name.toString()));
importedClasses.add(importedClass);
importedClasses.addAll(getAvailableClasses(name));
}
for (Class c : CompilationEnvironment.loadDefaultPackageClasses(source.getValue().getPkgName(), source.getKey(), classLoader)) {
for (Class c : CompilationEnvironment.loadDefaultPackageClasses(source.getValue().getPkgName(), source.getKey(), this)) {
ClassOrInterface importedClass = ASTFactory.createClass(c);
importedClasses.add(importedClass);
}
@@ -135,9 +159,6 @@ public class JavaTXCompiler {
void addMethods(SourceFile sf, ClassOrInterface cl, List<ClassOrInterface> importedClasses, ClassOrInterface objectClass) {
if (!cl.areMethodsAdded()) {
ClassOrInterface superclass = null;
if (cl.getSuperClass().getName().equals(new JavaClassName("java.lang.Object"))) {
superclass = objectClass;
} else {
Optional<ClassOrInterface> optSuperclass = importedClasses.stream().filter(x -> x.getClassName().equals(cl.getSuperClass().getName())).findFirst();
if (optSuperclass.isPresent()) {
superclass = optSuperclass.get();
@@ -147,10 +168,14 @@ public class JavaTXCompiler {
superclass = optSuperclass.get();
addMethods(sf, superclass, importedClasses, objectClass);
} else {
try {
var className = cl.getSuperClass().getName().toString();
superclass = ASTFactory.createClass(classLoader.loadClass(className));
} catch (ClassNotFoundException ignored) {}
// throw new ClassNotFoundException("");
}
}
}
Iterator<RefTypeOrTPHOrWildcardOrGeneric> paraIt = cl.getSuperClass().getParaList().iterator();
Iterator<GenericTypeVar> tvarVarIt = superclass.getGenerics().iterator();
@@ -163,7 +188,7 @@ public class JavaTXCompiler {
// werden
while (methodIt.hasNext()) {
Method m = methodIt.next();
ParameterList newParaList = new ParameterList(m.getParameterList().getFormalparalist().stream().map(fp -> new FormalParameter(fp.getName(), fp.getType().acceptTV(new TypeExchanger(gtvs)), fp.getOffset())).collect(Collectors.toCollection(ArrayList::new)), m.getParameterList().getOffset());
ParameterList newParaList = new ParameterList(m.getParameterList().getFormalparalist().stream().map(fp -> fp.withType(fp.getType().acceptTV(new TypeExchanger(gtvs)))).collect(Collectors.toCollection(ArrayList::new)), m.getParameterList().getOffset());
cl.getMethods().add(new Method(m.modifier, m.name, m.getReturnType().acceptTV(new TypeExchanger(gtvs)), newParaList, m.block,
// new GenericDeclarationList(newGenericsList,
// ((GenericDeclarationList)m.getGenerics()).getOffset()),
@@ -174,6 +199,19 @@ public class JavaTXCompiler {
cl.setMethodsAdded();
}
private List<ClassOrInterface> getAvailableClasses(JavaClassName name) throws ClassNotFoundException {
Set<ClassOrInterface> allClasses = new HashSet<>();
if (loadJavaTXClass(name)) {
var file = findFileForClass(name);
var sf = sourceFiles.get(file);
if (sf != null) allClasses.addAll(sf.KlassenVektor);
} else {
ClassOrInterface importedClass = ASTFactory.createClass(classLoader.loadClass(name.toString()));
allClasses.add(importedClass);
}
return new ArrayList<>(allClasses);
}
public List<ClassOrInterface> getAvailableClasses(SourceFile forSourceFile) throws ClassNotFoundException {
// PL 2018-09-18: List durch Set ersetzt, damit die Klassen nur einmal
// hinzugefuegt werden
@@ -181,22 +219,8 @@ public class JavaTXCompiler {
// ArrayList<>();//environment.getAllAvailableClasses();
Set<ClassOrInterface> allClasses = new HashSet<>();
/*
* PL 2018-09-19 geloescht werden bereits in typeInference hinzugefuegt } allClasses.addAll(importedClasses);
*
* return new TYPE(sourceFiles.values(), allClasses).getConstraints(); }
*
* public List<ClassOrInterface> getAvailableClasses(SourceFile forSourceFile) throws ClassNotFoundException { // PL 2018-09-18: List durch Set ersetzt, damit die Klassen nur einmal // hinzugefuegt werden // List<ClassOrInterface> allClasses = new // ArrayList<>();//environment.getAllAvailableClasses(); Set<ClassOrInterface> allClasses = new HashSet<>();
*
* /* PL 2018-09-19 geloescht werden bereits in typeInference hinzugefuegt for (SourceFile sf : sourceFiles.values()) { allClasses.addAll(sf.getClasses()); }
*/
List<ClassOrInterface> importedClasses = new ArrayList<>();
for (JavaClassName name : forSourceFile.getImports()) {
// TODO: Hier werden imports von eigenen (.jav) Klassen nicht beachtet
ClassOrInterface importedClass = ASTFactory.createClass(classLoader.loadClass(name.toString()));
importedClasses.add(importedClass);
allClasses.addAll(importedClasses);
allClasses.addAll(getAvailableClasses(name));
}
return new ArrayList<>(allClasses);
}
@@ -251,7 +275,7 @@ public class JavaTXCompiler {
SourceFile sf = source.getValue();
allClasses.addAll(getAvailableClasses(sf));
allClasses.addAll(sf.getClasses());
allClasses.addAll(CompilationEnvironment.loadDefaultPackageClasses(sf.getPkgName(), source.getKey(), classLoader).stream().map(ASTFactory::createClass).collect(Collectors.toList()));
allClasses.addAll(CompilationEnvironment.loadDefaultPackageClasses(sf.getPkgName(), source.getKey(), this).stream().map(ASTFactory::createClass).collect(Collectors.toList()));
}
final ConstraintSet<Pair> cons = getConstraints();
@@ -260,7 +284,7 @@ public class JavaTXCompiler {
// urm.addUnifyResultListener(resultListener);
try {
logFile = logFile == null ? new FileWriter(new File("log_" + sourceFiles.keySet().iterator().next().getName())) : logFile;
IFiniteClosure finiteClosure = UnifyTypeFactory.generateFC(allClasses, logFile, classLoader);
IFiniteClosure finiteClosure = UnifyTypeFactory.generateFC(allClasses, logFile, getClassLoader());
System.out.println(finiteClosure);
urm = new UnifyResultModel(cons, finiteClosure);
urm.addUnifyResultListener(resultListener);
@@ -382,16 +406,12 @@ public class JavaTXCompiler {
SourceFile sf = source.getValue();
allClasses.addAll(getAvailableClasses(sf));
allClasses.addAll(sf.getClasses());
var newClasses = CompilationEnvironment.loadDefaultPackageClasses(sf.getPkgName(), source.getKey(), classLoader).stream().map(ASTFactory::createClass).collect(Collectors.toList());
var newClasses = CompilationEnvironment.loadDefaultPackageClasses(sf.getPkgName(), source.getKey(), this).stream().map(ASTFactory::createClass).collect(Collectors.toList());
for (var clazz : newClasses) {
var found = false;
for (var old : allClasses) {
if (clazz.getClassName().equals(old.getClassName())) {
found = true;
break;
}
}
if (!found)
// Don't load classes that get recompiled
if (sf.getClasses().stream().anyMatch(nf -> nf.getClassName().equals(clazz.getClassName())))
continue;
if (allClasses.stream().noneMatch(old -> old.getClassName().equals(clazz.getClassName())))
allClasses.add(clazz);
}
}
@@ -399,7 +419,9 @@ public class JavaTXCompiler {
final ConstraintSet<Pair> cons = getConstraints();
Set<Set<UnifyPair>> results = new HashSet<>();
try {
Writer logFile = log ? new FileWriter(new File(System.getProperty("user.dir") + "/logFiles/" + "log_" + sourceFiles.keySet().iterator().next().getName())) : new OutputStreamWriter(new NullOutputStream());
var logFolder = new File(System.getProperty("user.dir") + "/logFiles/");
if (log) logFolder.mkdirs();
Writer logFile = log ? new FileWriter(new File(logFolder, "log_" + sourceFiles.keySet().iterator().next().getName())) : new OutputStreamWriter(new NullOutputStream());
IFiniteClosure finiteClosure = UnifyTypeFactory.generateFC(allClasses, logFile, classLoader);
System.out.println(finiteClosure);
ConstraintSet<UnifyPair> unifyCons = UnifyTypeFactory.convert(cons);
@@ -624,11 +646,53 @@ public class JavaTXCompiler {
return usedTPH;
}
public final JavaClassRegistry classRegistry = new JavaClassRegistry();
private SourceFile parse(File sourceFile) throws IOException, java.lang.ClassNotFoundException {
SourceFileContext tree = JavaTXParser.parse(sourceFile);
SyntaxTreeGenerator generator = new SyntaxTreeGenerator(environment.getRegistry(tree, sourceFile, classLoader), new GenericsRegistry(null));
SourceFile ret = generator.convert(tree, environment.packageCrawler, classLoader);
return ret;
environment.addClassesToRegistry(classRegistry, tree, sourceFile, this);
SyntaxTreeGenerator generator = new SyntaxTreeGenerator(this, classRegistry, new GenericsRegistry(null));
var classes = new ArrayList<ClassOrInterface>();
var sf = new SourceFile(generator.pkgName, classes, generator.imports);
addSourceFile(sourceFile, sf);
generator.convert(classes, tree, environment.packageCrawler);
sf.imports.addAll(generator.imports);
return sf;
}
/**
* When an import tries to import a JavaTX class it first looks it up in the cache and
* if it doesn't exist it's going to compile it and add it to the source files list
* @param name
*/
public boolean loadJavaTXClass(JavaClassName name) {
var file = findFileForClass(name);
if (file != null) {
try {
var tree = JavaTXParser.parse(file);
classRegistry.addName(name.toString(), 0); // TODO This gets overwritten later, is it bad if we don't know this right away?
environment.addClassesToRegistry(classRegistry, tree, file, this);
SyntaxTreeGenerator generator = new SyntaxTreeGenerator(this, classRegistry, new GenericsRegistry(null));
var classes = new ArrayList<ClassOrInterface>();
var sf = new SourceFile(generator.pkgName, classes, generator.imports);
addSourceFile(file, sf);
generator.convert(classes, tree, environment.packageCrawler);
return true;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
return false;
}
public File findFileForClass(JavaClassName name) {
var packageName = name.getPackageName();
var className = name.getClassName().split("\\.")[0];
for (var cp : classPath) {
var file = new File(cp, packageName.replaceAll("\\.", "/") + "/" + className + ".jav");
if (file.exists()) return file;
}
return null;
}
public void generateBytecode() throws ClassNotFoundException, IOException {
@@ -681,10 +745,10 @@ public class JavaTXCompiler {
}
public synchronized Map<JavaClassName, byte[]> generateBytecode(SourceFile sf, List<ResultSet> typeInferenceResult) {
var converter = new ASTToTargetAST(typeInferenceResult, sf, classLoader);
var converter = new ASTToTargetAST(this, typeInferenceResult, sf, classLoader);
var generatedClasses = new HashMap<JavaClassName, byte[]>();
for (var clazz : sf.getClasses()) {
var codegen = new Codegen(converter.convert(clazz));
var codegen = new Codegen(converter.convert(clazz), this);
var code = codegen.generate();
generatedClasses.put(clazz.getClassName(), code);
converter.auxiliaries.forEach((name, source) -> {
@@ -7,6 +7,7 @@ import java.net.URL;
import java.util.*;
import com.google.common.collect.Lists;
import de.dhbwstuttgart.core.JavaTXCompiler;
import de.dhbwstuttgart.syntaxtree.ClassOrInterface;
import de.dhbwstuttgart.syntaxtree.factory.ASTFactory;
@@ -56,21 +57,22 @@ public class CompilationEnvironment {
this.packageCrawler = new PackageCrawler(librarys);
}
public JavaClassRegistry getRegistry(SourceFileContext tree, File sourceFile, ClassLoader classLoader) throws ClassNotFoundException, IOException {
public void addClassesToRegistry(JavaClassRegistry registry, SourceFileContext tree, File sourceFile, JavaTXCompiler compiler) throws ClassNotFoundException, IOException {
Map<String, Integer> allNames;
if (tree instanceof SrcfileContext srcfile) {
allNames = GatherNames.getNames((SrcfileContext) tree, packageCrawler, classLoader);
for (Class c : loadDefaultPackageClasses(getPackageName(srcfile), sourceFile, classLoader)) {
allNames = GatherNames.getNames((SrcfileContext) tree, packageCrawler, compiler);
for (Class c : loadDefaultPackageClasses(getPackageName(srcfile), sourceFile, compiler)) {
allNames.put(c.getName(), c.getTypeParameters().length);
}
return new JavaClassRegistry(allNames);
registry.addNames(allNames);
} else {
throw new NotImplementedException();
}
}
public static List<Class> loadDefaultPackageClasses(String packageName, File sourceFile, ClassLoader classLoader) throws IOException, ClassNotFoundException {
public static List<Class> loadDefaultPackageClasses(String packageName, File sourceFile, JavaTXCompiler compiler) throws IOException, ClassNotFoundException {
ClassLoader classLoader = compiler.getClassLoader();
List<Class> ret = new ArrayList<>();
// Set classLoader to include default package for this specific source file
File dir = sourceFile.getParentFile();
@@ -2,8 +2,11 @@ package de.dhbwstuttgart.parser.SyntaxTreeGenerator;
import de.dhbwstuttgart.exceptions.DebugException;
import de.dhbwstuttgart.parser.NullToken;
import de.dhbwstuttgart.parser.scope.JavaClassName;
import de.dhbwstuttgart.syntaxtree.ClassOrInterface;
import de.dhbwstuttgart.syntaxtree.GenericTypeVar;
import de.dhbwstuttgart.syntaxtree.Method;
import de.dhbwstuttgart.syntaxtree.Pattern;
import de.dhbwstuttgart.syntaxtree.factory.ASTFactory;
import de.dhbwstuttgart.syntaxtree.factory.UnifyTypeFactory;
import de.dhbwstuttgart.syntaxtree.type.*;
@@ -31,13 +34,36 @@ public class FCGenerator {
//PL 2018-09-18: gtvs vor die for-Schleife gezogen, damit immer die gleichen Typeplaceholder eingesetzt werden.
HashMap<String, RefTypeOrTPHOrWildcardOrGeneric> gtvs = new HashMap<>();
for(ClassOrInterface cly : availableClasses){
pairs.addAll(getSuperTypes(cly, availableClasses, gtvs, classLoader));
List<Pair> newPairs = getSuperTypes(cly, availableClasses, gtvs, classLoader);
pairs.addAll(newPairs);
//For all Functional Interfaces FI: FunN$$<... args auf dem Functional Interface ...> <. FI is added to FC
if (isFunctionalInterface(cly)) {
pairs.add(genImplFunType(cly, newPairs.get(0).TA1, gtvs));
}
}
return pairs;
}
private static Boolean isFunctionalInterface(ClassOrInterface cly) {
return (cly.isInterface() && (cly.isFunctionalInterface() || cly.getMethods().size() == 1));
}
private static Pair genImplFunType(ClassOrInterface cly, RefTypeOrTPHOrWildcardOrGeneric fIType, HashMap<String, RefTypeOrTPHOrWildcardOrGeneric> gtvs) {
for(Method m : cly.getMethods()) {
if (!java.lang.reflect.Modifier.isAbstract(m.modifier))
continue;
List<RefTypeOrTPHOrWildcardOrGeneric> tl =
(m.getParameterList().getFormalparalist()
.stream().map(p -> p.getType().acceptTV(new TypeExchanger(gtvs)))
.collect(Collectors.toList()));
tl.add(m.getReturnType().acceptTV(new TypeExchanger(gtvs)));
return new Pair(new RefType(new JavaClassName("Fun" + (tl.size()-1) + "$$"), tl, new NullToken()),
fIType);
}
return null; //kann nicht passieren, da die Methode nur aufgerufen wird wenn cl Functional Interface ist
}
@@ -0,0 +1,6 @@
package de.dhbwstuttgart.parser.SyntaxTreeGenerator;
import de.dhbwstuttgart.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric;
public record FieldEntry(String name, RefTypeOrTPHOrWildcardOrGeneric type, int modifiers) {
}
@@ -1,5 +1,6 @@
package de.dhbwstuttgart.parser.SyntaxTreeGenerator;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
@@ -8,6 +9,10 @@ import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import de.dhbwstuttgart.core.JavaTXCompiler;
import de.dhbwstuttgart.syntaxtree.*;
import de.dhbwstuttgart.syntaxtree.statement.*;
import de.dhbwstuttgart.syntaxtree.type.Void;
import org.antlr.v4.runtime.Token;
import de.dhbwstuttgart.exceptions.NotImplementedException;
@@ -34,11 +39,17 @@ import de.dhbwstuttgart.parser.antlr.Java17Parser.EqualityexpressionContext;
import de.dhbwstuttgart.parser.antlr.Java17Parser.ExpressionContext;
import de.dhbwstuttgart.parser.antlr.Java17Parser.FltLiteralContext;
import de.dhbwstuttgart.parser.antlr.Java17Parser.ForloopContext;
import de.dhbwstuttgart.parser.antlr.Java17Parser.GPatternContext;
import de.dhbwstuttgart.parser.antlr.Java17Parser.GuardedPatternContext;
import de.dhbwstuttgart.parser.antlr.Java17Parser.IdentifierContext;
import de.dhbwstuttgart.parser.antlr.Java17Parser.InstanceofexpressionContext;
import de.dhbwstuttgart.parser.antlr.Java17Parser.IntLiteralContext;
import de.dhbwstuttgart.parser.antlr.Java17Parser.LabeledRuleDefaultContext;
import de.dhbwstuttgart.parser.antlr.Java17Parser.LabeledRuleExprListContext;
import de.dhbwstuttgart.parser.antlr.Java17Parser.LabeledRulePatternContext;
import de.dhbwstuttgart.parser.antlr.Java17Parser.LabeledstmtContext;
import de.dhbwstuttgart.parser.antlr.Java17Parser.LambdaLVTIParameterContext;
import de.dhbwstuttgart.parser.antlr.Java17Parser.LambdaexpressionContext;
import de.dhbwstuttgart.parser.antlr.Java17Parser.LambdaExpression2Context;
import de.dhbwstuttgart.parser.antlr.Java17Parser.MathaddsubexpressionContext;
import de.dhbwstuttgart.parser.antlr.Java17Parser.MathmuldivmodexpressionContext;
import de.dhbwstuttgart.parser.antlr.Java17Parser.MethodCallContext;
@@ -46,81 +57,74 @@ import de.dhbwstuttgart.parser.antlr.Java17Parser.MethodcallexpressionContext;
import de.dhbwstuttgart.parser.antlr.Java17Parser.NewinstanceexpressionContext;
import de.dhbwstuttgart.parser.antlr.Java17Parser.NullLiteralContext;
import de.dhbwstuttgart.parser.antlr.Java17Parser.OrexpressionContext;
import de.dhbwstuttgart.parser.antlr.Java17Parser.PPatternContext;
import de.dhbwstuttgart.parser.antlr.Java17Parser.PatternContext;
import de.dhbwstuttgart.parser.antlr.Java17Parser.PostfixexpressionContext;
import de.dhbwstuttgart.parser.antlr.Java17Parser.PrefixexpressionContext;
import de.dhbwstuttgart.parser.antlr.Java17Parser.PrimaryClassrefContext;
import de.dhbwstuttgart.parser.antlr.Java17Parser.PrimaryExpressionContext;
import de.dhbwstuttgart.parser.antlr.Java17Parser.PrimaryIdentifierContext;
import de.dhbwstuttgart.parser.antlr.Java17Parser.PrimaryLiteralContext;
import de.dhbwstuttgart.parser.antlr.Java17Parser.PrimaryPatternContext;
import de.dhbwstuttgart.parser.antlr.Java17Parser.PrimarySuperContext;
import de.dhbwstuttgart.parser.antlr.Java17Parser.PrimaryThisContext;
import de.dhbwstuttgart.parser.antlr.Java17Parser.PrimaryexpressionContext;
import de.dhbwstuttgart.parser.antlr.Java17Parser.PrimaryExpression2Context;
import de.dhbwstuttgart.parser.antlr.Java17Parser.RPatternContext;
import de.dhbwstuttgart.parser.antlr.Java17Parser.RecordPatternContext;
import de.dhbwstuttgart.parser.antlr.Java17Parser.RelationalexpressionContext;
import de.dhbwstuttgart.parser.antlr.Java17Parser.ReturnstmtContext;
import de.dhbwstuttgart.parser.antlr.Java17Parser.SemistmtContext;
import de.dhbwstuttgart.parser.antlr.Java17Parser.ShiftexpressionContext;
import de.dhbwstuttgart.parser.antlr.Java17Parser.StmtexpressionContext;
import de.dhbwstuttgart.parser.antlr.Java17Parser.StringLiteralContext;
import de.dhbwstuttgart.parser.antlr.Java17Parser.SwitchexpressionstmtContext;
import de.dhbwstuttgart.parser.antlr.Java17Parser.SwitchBlockStatementGroupContext;
import de.dhbwstuttgart.parser.antlr.Java17Parser.SwitchLabelConstContext;
import de.dhbwstuttgart.parser.antlr.Java17Parser.SwitchLabelContext;
import de.dhbwstuttgart.parser.antlr.Java17Parser.SwitchLabelDefaultContext;
import de.dhbwstuttgart.parser.antlr.Java17Parser.SwitchLabelPatternContext;
import de.dhbwstuttgart.parser.antlr.Java17Parser.SwitchLabeledRuleContext;
import de.dhbwstuttgart.parser.antlr.Java17Parser.SwitchRuleOutcomeContext;
import de.dhbwstuttgart.parser.antlr.Java17Parser.SwitchExpression2Context;
import de.dhbwstuttgart.parser.antlr.Java17Parser.SwitchstmtContext;
import de.dhbwstuttgart.parser.antlr.Java17Parser.SynchronizedstmtContext;
import de.dhbwstuttgart.parser.antlr.Java17Parser.TPatternContext;
import de.dhbwstuttgart.parser.antlr.Java17Parser.ThrowstmtContext;
import de.dhbwstuttgart.parser.antlr.Java17Parser.TrycatchblockContext;
import de.dhbwstuttgart.parser.antlr.Java17Parser.TrycatchresourceContext;
import de.dhbwstuttgart.parser.antlr.Java17Parser.TypePatternContext;
import de.dhbwstuttgart.parser.antlr.Java17Parser.WhileloopContext;
import de.dhbwstuttgart.parser.antlr.Java17Parser.YieldstmtContext;
import de.dhbwstuttgart.parser.scope.GenericsRegistry;
import de.dhbwstuttgart.parser.scope.JavaClassName;
import de.dhbwstuttgart.parser.scope.JavaClassRegistry;
import de.dhbwstuttgart.syntaxtree.FormalParameter;
import de.dhbwstuttgart.syntaxtree.ParameterList;
import de.dhbwstuttgart.syntaxtree.statement.ArgumentList;
import de.dhbwstuttgart.syntaxtree.statement.Assign;
import de.dhbwstuttgart.syntaxtree.statement.AssignLeftSide;
import de.dhbwstuttgart.syntaxtree.statement.AssignToField;
import de.dhbwstuttgart.syntaxtree.statement.BinaryExpr;
import de.dhbwstuttgart.syntaxtree.statement.Block;
import de.dhbwstuttgart.syntaxtree.statement.CastExpr;
import de.dhbwstuttgart.syntaxtree.statement.DoStmt;
import de.dhbwstuttgart.syntaxtree.statement.Expression;
import de.dhbwstuttgart.syntaxtree.statement.ExpressionReceiver;
import de.dhbwstuttgart.syntaxtree.statement.FieldVar;
import de.dhbwstuttgart.syntaxtree.statement.IfStmt;
import de.dhbwstuttgart.syntaxtree.statement.LambdaExpression;
import de.dhbwstuttgart.syntaxtree.statement.Literal;
import de.dhbwstuttgart.syntaxtree.statement.LocalVar;
import de.dhbwstuttgart.syntaxtree.statement.LocalVarDecl;
import de.dhbwstuttgart.syntaxtree.statement.MethodCall;
import de.dhbwstuttgart.syntaxtree.statement.NewClass;
import de.dhbwstuttgart.syntaxtree.statement.Receiver;
import de.dhbwstuttgart.syntaxtree.statement.Return;
import de.dhbwstuttgart.syntaxtree.statement.ReturnVoid;
import de.dhbwstuttgart.syntaxtree.statement.Statement;
import de.dhbwstuttgart.syntaxtree.statement.StaticClassName;
import de.dhbwstuttgart.syntaxtree.statement.Super;
import de.dhbwstuttgart.syntaxtree.statement.This;
import de.dhbwstuttgart.syntaxtree.statement.UnaryExpr;
import de.dhbwstuttgart.syntaxtree.statement.WhileStmt;
import de.dhbwstuttgart.syntaxtree.type.RefType;
import de.dhbwstuttgart.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric;
import de.dhbwstuttgart.syntaxtree.type.TypePlaceholder;
public class StatementGenerator {
private JavaClassRegistry reg;
private Map<String, RefTypeOrTPHOrWildcardOrGeneric> fields; // PL 2018-11-01 fields eingefuegt, damit die fields
// immer die gleiche TPH bekommen
private Map<String, RefTypeOrTPHOrWildcardOrGeneric> localVars;
private GenericsRegistry generics;
private final JavaClassRegistry reg;
public StatementGenerator(JavaClassRegistry reg, GenericsRegistry generics, Map<String, RefTypeOrTPHOrWildcardOrGeneric> fields, Map<String, RefTypeOrTPHOrWildcardOrGeneric> localVars) {
private final Map<String, FieldEntry> fields; // PL 2018-11-01 fields eingefuegt, damit die fields
// immer die gleiche TPH bekommen
private final Map<String, RefTypeOrTPHOrWildcardOrGeneric> localVars;
private final GenericsRegistry generics;
private final JavaTXCompiler compiler;
private final RefType superClass;
// TODO How about instead of passing all of these types we just pass an instance of the SyntaxTreeGenerator?
public StatementGenerator(RefType superType, JavaTXCompiler compiler, JavaClassRegistry reg, GenericsRegistry generics, Map<String, FieldEntry> fields, Map<String, RefTypeOrTPHOrWildcardOrGeneric> localVars) {
this.reg = reg;
this.generics = generics;
this.fields = fields;
this.localVars = localVars;
this.compiler = compiler;
this.superClass = superType;
}
public ParameterList convert(Java17Parser.FormalParameterListContext formalParameterListContext) {
List<FormalParameter> ret = new ArrayList<>();
List<Pattern> ret = new ArrayList<>();
List<Java17Parser.FormalParameterContext> fps = new ArrayList<>();
if (Objects.isNull(formalParameterListContext))
return new ParameterList(ret, new NullToken()); // Dann ist die Parameterliste leer
@@ -133,6 +137,9 @@ public class StatementGenerator {
fps = formalParameterListContext.formalParameter();
for (Java17Parser.FormalParameterContext fp : fps) {
if (fp.pattern() != null) {
ret.add(convert(fp.pattern()));
} else {
String paramName = SyntaxTreeGenerator.convert(fp.variableDeclaratorId());
RefTypeOrTPHOrWildcardOrGeneric type;
if (fp.typeType() != null) {
@@ -143,6 +150,7 @@ public class StatementGenerator {
ret.add(new FormalParameter(paramName, type, fp.getStart()));
localVars.put(paramName, type);
}
}
return new ParameterList(ret, ret.get(0).getOffset());
}
@@ -162,8 +170,6 @@ public class StatementGenerator {
return convert(dowhileloop);
case SwitchstmtContext switchstmt:
return convert(switchstmt);
case SwitchexpressionstmtContext switchexpression:
return convert(switchexpression);
case ReturnstmtContext returnstmt:
return convert(returnstmt);
case YieldstmtContext yieldstmt:
@@ -243,7 +249,12 @@ public class StatementGenerator {
ret = convert(prefix);
ret.setStatement();
return ret;
case SwitchExpression2Context switchexpr:
ret = convert(switchexpr);
ret.setStatement();
return ret;
default:
System.out.println(stmt.getClass());
throw new NotImplementedException();
}
}
@@ -317,23 +328,152 @@ public class StatementGenerator {
}
private Statement convert(Java17Parser.SwitchstmtContext stmt) {
// TODO
throw new NotImplementedException();
Expression switched = convert(stmt.parExpression().expression());
List<SwitchBlock> switchBlocks = new ArrayList<>();
for (SwitchBlockStatementGroupContext blockstmt : stmt.switchBlockStatementGroup()) {
switchBlocks.add(convert(blockstmt));
}
return new Switch(switched, switchBlocks, TypePlaceholder.fresh(switched.getOffset()), true, stmt.getStart());
}
private Statement convert(Java17Parser.SwitchexpressionstmtContext switchexpression) {
// TODO
throw new NotImplementedException();
// Um switchExpressions als Statement zu behandeln
private Statement convert(Java17Parser.SwitchExpression2Context switchexpression) {
Expression switchExpr = convert(switchexpression.switchExpression());
if (switchExpr instanceof Switch s) {
s.setStatement();
return s;
} else {
// sollte nie vorkommen, da convert(Java17Parser.SwitchExpressionContext switchExpression) eine Instanz von Switch zurückgibt
throw new RuntimeException();
}
}
private Expression convert(Java17Parser.SwitchExpressionContext switchExpression) {
Expression switched = convert(switchExpression.parExpression().expression());
List<SwitchBlock> switchBlocks = new ArrayList<>();
Token offset = switchExpression.getStart();
for (SwitchLabeledRuleContext labeledRule : switchExpression.switchLabeledRule()) {
switchBlocks.add(convert(labeledRule));
}
return new Switch(switched, switchBlocks, TypePlaceholder.fresh(offset), false, offset);
}
private SwitchBlock convert(SwitchLabeledRuleContext labeledRule) {
Boolean isDefault = false;
List<SwitchLabel> labels = switch (labeledRule.switchLabelCase()) {
case LabeledRuleExprListContext exprList -> {
List<SwitchLabel> labelList = exprList.expressionList().expression().stream().map((exprctx) -> {
Pattern expr = new ExpressionPattern(convert(exprctx), exprList.getStart());
return new SwitchLabel(expr, expr.getType(), exprList.getStart());
}).toList();
yield labelList;
}
case LabeledRulePatternContext pattern -> {
Pattern p = convert(pattern.pattern());
yield Arrays.asList(new SwitchLabel(p, p.getType(), pattern.getStart()));
}
case LabeledRuleDefaultContext def -> {
isDefault = true;
yield Arrays.asList(new SwitchLabel(new Void(def.getStart()), def.getStart()));
}
default -> throw new NotImplementedException();
};
var isSingleExpression = false;
Token offset = labeledRule.getStart();
SwitchRuleOutcomeContext outcome = labeledRule.switchRuleOutcome();
Block block;
if (Objects.isNull(outcome.block())) {
List<Statement> stmts = new ArrayList<>();
stmts.add(new Yield(convert(outcome.expression()), outcome.expression().start));
isSingleExpression = true;
block = new Block(stmts, outcome.expression().getStart());
} else {
block = convert(outcome.block(), false);
}
return new SwitchBlock(labels, block, isDefault, isSingleExpression, offset);
}
private Statement convert(Java17Parser.YieldstmtContext yieldstmt) {
// TODO
throw new NotImplementedException();
return new Yield(convert(yieldstmt.expression()), yieldstmt.getStart());
}
private Statement convert(Java17Parser.SwitchBlockStatementGroupContext stmt) {
// TODO
private SwitchBlock convert(Java17Parser.SwitchBlockStatementGroupContext stmt) {
List<SwitchLabel> labels = new ArrayList<>();
stmt.switchLabel().forEach((label) -> {
labels.add(convert(label));
});
List<Statement> block = new ArrayList<>();
stmt.blockStatement().stream().forEach((blockStmt) -> {
block.addAll(convert(blockStmt));
});
return new SwitchBlock(labels, new Block(block, stmt.blockStatement(0).getStart()), false, stmt.getStart());
}
private SwitchLabel convert(SwitchLabelContext switchLabel) {
RefTypeOrTPHOrWildcardOrGeneric type = null;
Pattern caseExpression = switch (switchLabel) {
case SwitchLabelConstContext cons -> {
yield new ExpressionPattern(convert(cons.constantExpression), cons.getStart());
}
case SwitchLabelPatternContext pattern -> {
yield convert(pattern.pattern());
}
case SwitchLabelDefaultContext def -> {
type = new Void(switchLabel.getStart());
yield null;
}
default -> throw new NotImplementedException();
};
Token offset = switchLabel.getStart();
if (Objects.isNull(caseExpression)) {
if (type == null)
type = TypePlaceholder.fresh(offset);
return new SwitchLabel(type, offset);
} else {
return new SwitchLabel(caseExpression, caseExpression.getType(), offset);
}
}
private Pattern convert(PatternContext pattern) {
return switch (pattern) {
case PPatternContext pPattern -> {
yield convert(pPattern.primaryPattern());
}
case GPatternContext gPattern -> {
GuardedPatternContext guarded = gPattern.guardedPattern();
Expression condition = convert(guarded.expression());
yield new GuardedPattern(condition, convert(guarded.primaryPattern()), guarded.getStart());
}
default -> throw new NotImplementedException();
};
}
private FormalParameter convert(PrimaryPatternContext pPattern) {
switch (pPattern) {
case TPatternContext tPattern:
TypePatternContext typePattern = tPattern.typePattern();
var text = typePattern.identifier().getText();
var type = TypeGenerator.convert(typePattern.typeType(), reg, generics);
localVars.put(text, type);
return new FormalParameter(text, type, typePattern.getStart());
case RPatternContext rPattern:
RecordPatternContext recordPattern = rPattern.recordPattern();
return convert(recordPattern);
default:
throw new NotImplementedException();
}
}
private RecordPattern convert(RecordPatternContext recordPatternCtx) {
List<PatternContext> subPatternCtx = recordPatternCtx.recordStructurePattern().recordComponentPatternList().pattern();
List<Pattern> subPattern = subPatternCtx.stream().map(this::convert).collect(Collectors.toList());
IdentifierContext identifierCtx = recordPatternCtx.identifier();
var text = (identifierCtx != null) ? identifierCtx.getText() : null;
var type = TypeGenerator.convert(recordPatternCtx.typeType(), reg, generics);
if (text != null) localVars.put(text, type);
return new RecordPattern(subPattern, text, type, recordPatternCtx.getStart());
}
private Statement convert(Java17Parser.WhileloopContext stmt) {
@@ -349,7 +489,18 @@ public class StatementGenerator {
}
private Statement convert(Java17Parser.ForloopContext stmt) {
var control = stmt.forControl();
var block = convert(stmt.statement());
if (control.enhancedForControl() != null)
throw new NotImplementedException();
else {
return new ForStmt(
stmt.getStart(),
convert(control.forInit().localVariableDeclaration()),
convert(control.expression()), control.forUpdate.expression().stream().map(this::convert).toList(),
block
);
}
}
private ArgumentList convertArguments(Java17Parser.ExpressionListContext arglist) {
@@ -410,12 +561,18 @@ public class StatementGenerator {
} else {
initValue = convert(varDecl.variableInitializer().expression());
}
return (new Assign(new AssignToField(new FieldVar(new This(varDecl.getStart()), name.getText(), type, varDecl.getStart())), initValue, name.getStart()));
var fieldEntry = fields.get(name.getText());
return (new Assign(new AssignToField(new FieldVar(new This(varDecl.getStart()), (fieldEntry.modifiers() & Modifier.STATIC) != 0, name.getText(), type, varDecl.getStart())), initValue, name.getStart()));
}
private Statement convert(Java17Parser.BreakstmtContext stmt) {
// TODO
throw new NotImplementedException();
Token offset = stmt.getStart();
if (!Objects.isNull(stmt.identifier())) {
return new Break(localVars.get(stmt.identifier().getText()), offset);
} else {
return new Break(TypePlaceholder.fresh(offset), offset);
}
}
private Statement convert(Java17Parser.ContinuestmtContext stmt) {
@@ -462,7 +619,7 @@ public class StatementGenerator {
private Expression convert(Java17Parser.ExpressionContext expression) {
switch (expression) {
case PrimaryexpressionContext primary:
case PrimaryExpression2Context primary:
return convert(primary.primary());
case DottedexpressionContext dotted:
return convert(dotted, expression.getStart());
@@ -482,14 +639,15 @@ public class StatementGenerator {
return convert(mathexpr);
case RelationalexpressionContext comparison:
return convert(comparison);
/*
* TODO: syntaxtree for instanceof vorbereiten case InstanceofexpressionContext instanceof: case SwitchexpressionContext switchexpression:
*/
case InstanceofexpressionContext instanceOf:
return convert(instanceOf);
case SwitchExpression2Context switchexpression:
return convert(switchexpression.switchExpression());
case EqualityexpressionContext equal:
return convert(equal);
case AssignexpressionContext assignment:
return convert(assignment);
case LambdaexpressionContext lambdaexpr:
case LambdaExpression2Context lambdaexpr:
return convert(lambdaexpr.lambdaExpression());
case ArrayaccessexpressionContext arrayaccess:
return convert(arrayaccess);
@@ -562,7 +720,7 @@ public class StatementGenerator {
public Receiver getReceiver(ExpressionContext expr) {
Expression expression = convert(expr);
/*
* if (expr instanceof PrimaryexpressionContext pc) { expression = convert(pc.primary()); } else { expression = generateLocalOrFieldVarOrClassName(expr.getText(), expr.getStart()); }
* if (expr instanceof PrimaryExpression2Context pc) { expression = convert(pc.primary()); } else { expression = generateLocalOrFieldVarOrClassName(expr.getText(), expr.getStart()); }
*/
return getReceiver(expression);
}
@@ -588,16 +746,15 @@ public class StatementGenerator {
// Check for localVar:
if (localVars.get(expression) != null) {
return new LocalVar(expression, localVars.get(expression), offset);
} else {
if (fields.get(expression) != null) {// PL 2018-11-01 fields eingefuegt, damit die fields immer die
} else if (fields.get(expression) != null) {// PL 2018-11-01 fields eingefuegt, damit die fields immer die
// gleiche TPH bekommen
return new FieldVar(new This(offset), expression, fields.get(expression), offset);
var field = fields.get(expression);
return new FieldVar(new This(offset), Modifier.isStatic(field.modifiers()), expression, fields.get(expression).type(), offset);
} else {
// kann eigentlich nicht vorkommen
// Dann Muss es ein Feld sein!
return new FieldVar(new This(offset), expression, TypePlaceholder.fresh(offset), offset);
}
// lokale Variable wurde ohne "var"-Keyword deklariert und direkt mit Wert versehen
localVars.put(expression, TypePlaceholder.fresh(offset));
return new LocalVar(expression, localVars.get(expression), offset);
}
}
return generateFieldVarOrClassname(expression, offset);
@@ -615,16 +772,24 @@ public class StatementGenerator {
}
whole += ".";
}
var fieldName = parts[parts.length - 1];
var isStatic = false;
if (parts.length < 2 || parts[0].contentEquals("this")) {
receiver = new This(offset);
isStatic = Modifier.isStatic(fields.get(fieldName).modifiers());
} else if (parts[0].contentEquals("super")) {
receiver = new Super(offset);
isStatic = Modifier.isStatic(compiler.getClass(new JavaClassName(superClass.getName().toString())).getField(fieldName).orElseThrow().modifier);
} else if (receiver == null) { // Handelt es sich um keinen Statischen Klassennamen:
String part = expression.substring(0, expression.length() - (1 + parts[parts.length - 1].length()));
receiver = generateLocalOrFieldVarOrClassName(part, offset);
} else {
StaticClassName cname = (StaticClassName) receiver;
var javaClassName = reg.getName(cname.getType().toString());
isStatic = Modifier.isStatic(compiler.getClass(javaClassName).getField(fieldName).orElseThrow().modifier);
}
return new FieldVar(receiver, parts[parts.length - 1], TypePlaceholder.fresh(offset), offset);
return new FieldVar(receiver, isStatic, fieldName, TypePlaceholder.fresh(offset), offset);
}
private Expression convert(Java17Parser.ArrayaccessexpressionContext arrayaccess) {
@@ -636,11 +801,19 @@ public class StatementGenerator {
}
private Expression convert(Java17Parser.OrexpressionContext expression) {
if (expression.expression().size() != 2) {
throw new NotImplementedException();
} else {
return new BoolExpression(BoolExpression.Operator.OR, new RefType(new JavaClassName("java.lang.Boolean"), expression.getStart()), convert(expression.expression(0)), convert(expression.expression(1)), expression.getStart());
}
}
private Expression convert(Java17Parser.AndexpressionContext expression) {
if (expression.expression().size() != 2) {
throw new NotImplementedException();
} else {
return new BoolExpression(BoolExpression.Operator.AND, new RefType(new JavaClassName("java.lang.Boolean"), expression.getStart()), convert(expression.expression(0)), convert(expression.expression(1)), expression.getStart());
}
}
private Statement convert(AssignexpressionContext expr) {
@@ -700,6 +873,30 @@ public class StatementGenerator {
return new BinaryExpr(convertBinaryOperator(operator), TypePlaceholder.fresh(expression.getStart()), convert(expression.expression(0)), convert(expression.expression(1)), expression.getStart());
}
private Expression convert(Java17Parser.InstanceofexpressionContext expression) {
Expression left = convert(expression.expression());
Token offset = expression.getStart();
if (Objects.isNull(expression.pattern())) {;
return new InstanceOf(left, new RefType(reg.getName("java.lang.Boolean"), expression.getStart()), TypeGenerator.convert(expression.typeType(), reg, generics), offset);
} else {
switch (expression.pattern()) {
case PPatternContext primaryPattern:
switch (primaryPattern.primaryPattern()) {
case TPatternContext typePattern:
TypePatternContext typePatternCtx = typePattern.typePattern();
String localVarName = typePatternCtx.identifier().getText();
RefTypeOrTPHOrWildcardOrGeneric localVarType = TypeGenerator.convert(typePatternCtx.typeType(), reg, generics);
localVars.put(localVarName, localVarType);
return new InstanceOf(left, new RefType(reg.getName("java.lang.Boolean"), expression.getStart()), new FormalParameter(localVarName, localVarType, typePatternCtx.getStart()), offset);
default:
throw new NotImplementedException();
}
default:
throw new NotImplementedException();
}
}
}
private BinaryExpr.Operator convertBinaryOperator(String operator) {
// return BinaryExpr.Operator.ADD;
if (operator.equals("+")) {
@@ -837,7 +1034,7 @@ public class StatementGenerator {
Java17Parser.LambdaParametersContext lambdaParams = expression.lambdaParameters();
ParameterList params;
if (lambdaParams.identifier().size() > 0) {
List<FormalParameter> parameterList = new ArrayList<>();
List<Pattern> parameterList = new ArrayList<>();
for (IdentifierContext identifier : lambdaParams.identifier()) {
Token offset = identifier.getStart();
parameterList.add(new FormalParameter(identifier.getText(), TypePlaceholder.fresh(offset), offset));
@@ -847,7 +1044,7 @@ public class StatementGenerator {
params = convert(lambdaParams.formalParameterList());
// }else if( lambdaParams.inferredFormalParameterList != null){
} else if (!Objects.isNull(lambdaParams.lambdaLVTIList())) {
List<FormalParameter> parameterList = new ArrayList<>();
List<Pattern> parameterList = new ArrayList<>();
for (LambdaLVTIParameterContext param : lambdaParams.lambdaLVTIList().lambdaLVTIParameter()) {
Token offset = param.getStart();
parameterList.add(new FormalParameter(param.identifier().getText(), TypePlaceholder.fresh(offset), offset));
@@ -859,10 +1056,11 @@ public class StatementGenerator {
HashMap<String, RefTypeOrTPHOrWildcardOrGeneric> lambdaLocals = new HashMap<>();
lambdaLocals.putAll(localVars);
for (FormalParameter param : params.getFormalparalist()) {
lambdaLocals.put(param.getName(), param.getType());
for (Pattern param : params.getFormalparalist()) {
if (!(param instanceof FormalParameter fp)) throw new IllegalArgumentException();
lambdaLocals.put(fp.getName(), fp.getType());
}
StatementGenerator lambdaGenerator = new StatementGenerator(reg, generics, fields, lambdaLocals);
StatementGenerator lambdaGenerator = new StatementGenerator(superClass, compiler, reg, generics, fields, lambdaLocals);
Block block;
if (expression.lambdaBody().expression() != null) {
@@ -12,6 +12,10 @@ import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import de.dhbwstuttgart.core.JavaTXCompiler;
import de.dhbwstuttgart.parser.NullToken;
import de.dhbwstuttgart.syntaxtree.*;
import de.dhbwstuttgart.syntaxtree.Record;
import org.antlr.v4.runtime.CommonToken;
import org.antlr.v4.runtime.Token;
@@ -54,22 +58,13 @@ import de.dhbwstuttgart.parser.antlr.Java17Parser.ModifierContext;
import de.dhbwstuttgart.parser.antlr.Java17Parser.NoclassorinterfaceContext;
import de.dhbwstuttgart.parser.antlr.Java17Parser.RecordComponentContext;
import de.dhbwstuttgart.parser.antlr.Java17Parser.RecordDeclarationContext;
import de.dhbwstuttgart.parser.antlr.Java17Parser.ReftypeContext;
import de.dhbwstuttgart.parser.antlr.Java17Parser.RefType2Context;
import de.dhbwstuttgart.parser.antlr.Java17Parser.SrcfileContext;
import de.dhbwstuttgart.parser.antlr.Java17Parser.TypeArgumentsContext;
import de.dhbwstuttgart.parser.scope.GatherNames;
import de.dhbwstuttgart.parser.scope.GenericsRegistry;
import de.dhbwstuttgart.parser.scope.JavaClassName;
import de.dhbwstuttgart.parser.scope.JavaClassRegistry;
import de.dhbwstuttgart.syntaxtree.ClassOrInterface;
import de.dhbwstuttgart.syntaxtree.Constructor;
import de.dhbwstuttgart.syntaxtree.Field;
import de.dhbwstuttgart.syntaxtree.FormalParameter;
import de.dhbwstuttgart.syntaxtree.GenericDeclarationList;
import de.dhbwstuttgart.syntaxtree.Method;
import de.dhbwstuttgart.syntaxtree.ParameterList;
import de.dhbwstuttgart.syntaxtree.Record;
import de.dhbwstuttgart.syntaxtree.SourceFile;
import de.dhbwstuttgart.syntaxtree.factory.ASTFactory;
import de.dhbwstuttgart.syntaxtree.statement.Assign;
import de.dhbwstuttgart.syntaxtree.statement.AssignLeftSide;
@@ -85,20 +80,27 @@ import de.dhbwstuttgart.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric;
import de.dhbwstuttgart.syntaxtree.type.TypePlaceholder;
import de.dhbwstuttgart.syntaxtree.type.Void;
import de.dhbwstuttgart.typeinference.constraints.GenericsResolver;
import javassist.compiler.SyntaxError;
import javax.swing.text.html.Option;
public class SyntaxTreeGenerator {
private JavaClassRegistry reg;
private final GenericsRegistry globalGenerics;
private String pkgName = "";
Set<JavaClassName> imports = new HashSet<>();
public String pkgName = "";
public Set<JavaClassName> imports = new HashSet<>();
HashMap<String, Integer> allmodifiers = new HashMap<>();
// PL 2018-11-01 fields eingefuegt, damit die fields immer die gleiche TPH
// bekommen
private Map<String, RefTypeOrTPHOrWildcardOrGeneric> fields = new HashMap<>();
private final Map<String, FieldEntry> fields = new HashMap<>();
// PL 2019-10-23: Muss für jede Klasse neu initilisiert werden
List<Statement> fieldInitializations = new ArrayList<>();
List<Statement> staticFieldInitializations = new ArrayList<>();
public SyntaxTreeGenerator(JavaClassRegistry reg, GenericsRegistry globalGenerics) {
private final JavaTXCompiler compiler;
private RefType superClass;
public SyntaxTreeGenerator(JavaTXCompiler compiler, JavaClassRegistry reg, GenericsRegistry globalGenerics) {
// Die Generics müssen während des Bauens des AST erstellt werden,
// da diese mit der Methode oder Klasse, in welcher sie deklariert werden
// verknüpft sein müssen. Dennoch werden die Namen aller Generics in einer
@@ -121,6 +123,8 @@ public class SyntaxTreeGenerator {
this.allmodifiers.put("non-sealed", 8192);
this.allmodifiers.put("default", 16384);
this.allmodifiers.put("strictfp", 32768);
this.compiler = compiler;
}
public JavaClassRegistry getReg() {
@@ -134,17 +138,16 @@ public class SyntaxTreeGenerator {
return ctx.getText();
}
public SourceFile convert(Java17Parser.SourceFileContext ctx, PackageCrawler packageCrawler, ClassLoader classLoader) throws ClassNotFoundException, NotImplementedException {
public void convert(List<ClassOrInterface> classes, Java17Parser.SourceFileContext ctx, PackageCrawler packageCrawler) throws ClassNotFoundException, NotImplementedException {
SrcfileContext srcfile;
List<ClassOrInterface> classes = new ArrayList<>();
if (ctx instanceof Java17Parser.SrcfileContext) {
srcfile = (SrcfileContext) ctx;
} else {
return new SourceFile(this.pkgName, classes, this.imports);
return;
}
if (srcfile.packageDeclaration() != null)
this.pkgName = convert(srcfile.packageDeclaration());
Map<String, Integer> imports = GatherNames.getImports(srcfile, packageCrawler, classLoader);
Map<String, Integer> imports = GatherNames.getImports(srcfile, packageCrawler, compiler);
this.imports = imports.keySet().stream().map(name -> reg.getName(name)).collect(Collectors.toSet());
for (Java17Parser.ClassOrInterfaceContext type : srcfile.classOrInterface()) {
ClassorinterfacedeclContext clsoif;
@@ -161,6 +164,7 @@ public class SyntaxTreeGenerator {
}
}
fieldInitializations = new ArrayList<>(); // PL 2019-10-22: muss für jede Klasse neu initilisiert werden
staticFieldInitializations = new ArrayList<>();
if (!Objects.isNull(clsoif.classDeclaration())) {
newClass = convertClass(clsoif.classDeclaration(), modifiers);
} else if (!Objects.isNull(clsoif.interfaceDeclaration())) {
@@ -172,9 +176,7 @@ public class SyntaxTreeGenerator {
}
classes.add(newClass);
}
if (classes.size() > 0) {
return new SourceFile(this.pkgName, classes, this.imports);
} else {
if (classes.isEmpty()) {
throw new NotImplementedException("SourceFile enthält keine Klassen");
}
}
@@ -193,7 +195,7 @@ public class SyntaxTreeGenerator {
Token offset = ctx.getStart();
GenericDeclarationList genericClassParameters;
if (ctx.genericDeclarationList() == null) {
genericClassParameters = new GenericDeclarationList(new ArrayList<>(), ctx.identifier().getStop());
genericClassParameters = new GenericDeclarationList(new ArrayList<>(), ctx.classBody().getStart());
} else {
genericClassParameters = TypeGenerator.convert(ctx.genericDeclarationList(), name, "", reg, generics);
}
@@ -203,10 +205,12 @@ public class SyntaxTreeGenerator {
} else {
superClass = new RefType(ASTFactory.createObjectClass().getClassName(), ctx.getStart());
}
this.superClass = superClass;
List<Field> fielddecl = new ArrayList<>();
List<Method> methods = new ArrayList<>();
List<Constructor> constructors = new ArrayList<>();
Boolean isInterface = false;
Boolean isFunctionalInterface = false;
List<RefType> implementedInterfaces = new ArrayList<>();
List<RefType> permittedSubtypes = new ArrayList<>();
for (ClassBodyDeclarationContext clsbodydecl : ctx.classBody().classBodyDeclaration()) {
@@ -220,24 +224,22 @@ public class SyntaxTreeGenerator {
}
// Ist Bit für 'sealed'-Modifier gesetzt
if ((modifiers & 4096) != 0) {
switch (ctx.typeList().size()) {
case 1: {
permittedSubtypes.addAll(convert(ctx.typeList(0), generics));
break;
}
case 2: {
permittedSubtypes.addAll(convert(ctx.typeList(1), generics));
break;
}
default: {
break;
if (!Objects.isNull(ctx.PERMITS())) {
// permitted subtypes sind letzte typeList (siehe Grammatikregel 'classDeclaration')
permittedSubtypes.addAll(convert(ctx.typeList(ctx.typeList().size() - 1), generics));
} else {
// falls sealed modifier ohne 'permits'-List oder umgekehrt
throw new NotImplementedException("Invalid sealed class declaration");
}
}
}
return new ClassOrInterface(modifiers, name, fielddecl, Optional.of(this.generatePseudoConstructor(ctx.identifier().getText(), name, superClass, genericClassParameters, offset)), methods, constructors, genericClassParameters, superClass, isInterface, implementedInterfaces, offset);
var ctor = Optional.of(this.generatePseudoConstructor(ctx.identifier().getText(), fieldInitializations, genericClassParameters, offset));
var staticCtor = Optional.of(this.generateStaticConstructor(ctx.identifier().getText(), staticFieldInitializations, genericClassParameters, offset));
return new ClassOrInterface(modifiers, name, fielddecl, ctor, staticCtor, methods, constructors, genericClassParameters, superClass, isInterface, isFunctionalInterface, implementedInterfaces, permittedSubtypes, offset);
}
private de.dhbwstuttgart.syntaxtree.Record convertRecord(RecordDeclarationContext recordDeclaration, int modifiers) {
this.superClass = new RefType(new JavaClassName("java.lang.Record"), new NullToken());
String identifier = recordDeclaration.identifier().getText();
String className = this.pkgName + (this.pkgName.length() > 0 ? "." : "") + identifier;
JavaClassName name = reg.getName(className); // Holt den Package Namen mit dazu
@@ -248,17 +250,17 @@ public class SyntaxTreeGenerator {
}
GenericDeclarationList genericClassParameters;
if (recordDeclaration.genericDeclarationList() == null) {
genericClassParameters = new GenericDeclarationList(new ArrayList<>(), recordDeclaration.identifier().getStop());
genericClassParameters = new GenericDeclarationList(new ArrayList<>(), recordDeclaration.recordBody().getStart());
} else {
genericClassParameters = TypeGenerator.convert(recordDeclaration.genericDeclarationList(), name, "", reg, generics);
}
RefType superClass = new RefType(ASTFactory.createObjectClass().getClassName(), offset);
RefType superClass = new RefType(ASTFactory.createClass(java.lang.Record.class).getClassName(), offset);
List<Field> fielddecl = new ArrayList<>();
List<Method> methods = new ArrayList<>();
List<Constructor> constructors = new ArrayList<>();
Boolean isInterface = false;
List<RefType> implementedInterfaces = new ArrayList<>();
List<FormalParameter> constructorParameters = new ArrayList<>();
List<Pattern> constructorParameters = new ArrayList<>();
List<Statement> constructorStatements = new ArrayList<>();
for (RecordComponentContext component : recordDeclaration.recordHeader().recordComponentList().recordComponent()) {
int fieldmodifiers = allmodifiers.get("private") + allmodifiers.get("final");
@@ -272,7 +274,7 @@ public class SyntaxTreeGenerator {
}
fielddecl.add(new Field(fieldname, fieldtype, fieldmodifiers, fieldoffset));
constructorParameters.add(new FormalParameter(fieldname, fieldtype, fieldoffset));
FieldVar fieldvar = new FieldVar(new This(offset), fieldname, fieldtype, fieldoffset);
FieldVar fieldvar = new FieldVar(new This(offset), false, fieldname, fieldtype, fieldoffset);
constructorStatements.add(new Assign(new AssignToField(fieldvar), new LocalVar(fieldname, fieldtype, fieldoffset), offset));
Statement returnStatement = new Return(fieldvar, offset);
methods.add(new Method(allmodifiers.get("public"), fieldname, fieldtype, new ParameterList(new ArrayList<>(), offset), new Block(Arrays.asList(returnStatement), offset), new GenericDeclarationList(new ArrayList<>(), offset), offset));
@@ -287,12 +289,12 @@ public class SyntaxTreeGenerator {
if (!Objects.isNull(recordDeclaration.IMPLEMENTS())) {
implementedInterfaces.addAll(convert(recordDeclaration.typeList(), generics));
}
return new Record(modifiers, name, fielddecl, initializations, methods, constructors, genericClassParameters, superClass, isInterface, implementedInterfaces, offset);
var staticCtor = Optional.of(this.generateStaticConstructor(recordDeclaration.identifier().getText(), staticFieldInitializations, genericClassParameters, offset));
return new Record(modifiers, name, fielddecl, initializations, staticCtor, methods, constructors, genericClassParameters, superClass, isInterface, implementedInterfaces, offset);
}
private void convert(ClassBodyDeclarationContext classBody, List<Field> fields, List<Constructor> constructors, List<Method> methods, JavaClassName name, RefType superClass, GenericsRegistry generics) {
MemberdeclContext member;
// Statement-Blöcke und "leere Zeilen" (;) werden noch nicht berücksichtigt
if (classBody instanceof MemberdeclContext) {
member = (MemberdeclContext) classBody;
Integer membermodifiers = 0;
@@ -323,10 +325,16 @@ public class SyntaxTreeGenerator {
default:
break;
}
} else if (classBody instanceof Java17Parser.ClassblockContext ctx && ctx.STATIC() != null) {
// Static blocks
var stmtgen = new StatementGenerator(superClass, compiler, reg, generics, this.fields, new HashMap<>());
var block = stmtgen.convert(((Java17Parser.ClassblockContext) classBody).block(), false);
staticFieldInitializations.addAll(block.statements);
}
}
private ClassOrInterface convertInterface(Java17Parser.InterfaceDeclarationContext ctx, int modifiers) {
this.superClass = new RefType(new JavaClassName("java.lang.Object"), new NullToken());
String className = this.pkgName.length() > 0 ? this.pkgName + "." : "" + ctx.identifier().getText();
JavaClassName name = reg.getName(className); // Holt den Package Namen mit dazu
if (!name.toString().equals(className)) { // Kommt die Klasse schon in einem anderen Package vor?
@@ -388,7 +396,20 @@ public class SyntaxTreeGenerator {
if (!Objects.isNull(ctx.EXTENDS())) {
extendedInterfaces.addAll(convert(ctx.typeList(0), generics));
}
return new ClassOrInterface(modifiers, name, fields, Optional.empty(), methods, new ArrayList<>(), genericParams, superClass, true, extendedInterfaces, ctx.getStart());
List<RefType> permittedSubtypes = new ArrayList<>();
// Ist Bit für 'sealed'-Modifier gesetzt
if ((modifiers & 4096) != 0) {
if (!Objects.isNull(ctx.PERMITS())) {
// permitted subtypes sind letzte typeList (siehe Grammatikregel 'classDeclaration')
permittedSubtypes.addAll(convert(ctx.typeList(ctx.typeList().size() - 1), generics));
} else {
// falls sealed modifier ohne 'permits'-List oder umgekehrt
throw new NotImplementedException("Invalid sealed class declaration");
}
}
var staticCtor = Optional.of(this.generateStaticConstructor(ctx.identifier().getText(), staticFieldInitializations, genericParams, ctx.getStart()));
return new ClassOrInterface(modifiers, name, fields, Optional.empty(), staticCtor, methods, new ArrayList<>(), genericParams, superClass, true, methods.size() == 1 ? true : false, extendedInterfaces, permittedSubtypes, ctx.getStart());
}
private GenericDeclarationList createEmptyGenericDeclarationList(Token classNameIdentifier) {
@@ -410,13 +431,13 @@ public class SyntaxTreeGenerator {
if (Objects.isNull(bodydeclaration.refType())) {
retType = TypePlaceholder.fresh(bodydeclaration.getStart());
} else {
if (bodydeclaration.refType() instanceof ReftypeContext reftype) {
if (bodydeclaration.refType() instanceof RefType2Context reftype) {
retType = TypeGenerator.convert(reftype.typeType(), reg, generics);
} else {
retType = new Void(bodydeclaration.refType().getStart());
}
}
StatementGenerator stmtgen = new StatementGenerator(reg, generics, fields, new HashMap<>());
StatementGenerator stmtgen = new StatementGenerator(superClass, compiler, reg, generics, fields, new HashMap<>());
ParameterList paramlist = stmtgen.convert(bodydeclaration.formalParameters().formalParameterList());
MethodBodyContext body = bodydeclaration.methodBody();
Block block = null;
@@ -444,15 +465,22 @@ public class SyntaxTreeGenerator {
/*
* fieldInitializations werden in einem Psedokonstruktor in der abstrakten Syntax gespeichert
*/
private Constructor generatePseudoConstructor(String className, JavaClassName parentClass, RefType superClass, GenericDeclarationList classGenerics, Token offset) {
private Constructor generatePseudoConstructor(String className, List<Statement> initializations, GenericDeclarationList classGenerics, Token offset) {
RefType classType = ClassOrInterface.generateTypeOfClass(reg.getName(className), classGenerics, offset);
ParameterList params = new ParameterList(new ArrayList<>(), offset);
Block block = new Block(new ArrayList<>(fieldInitializations), offset);
Block block = new Block(new ArrayList<>(initializations), offset);
return new Constructor(Modifier.PUBLIC, className, classType, params, block, classGenerics, offset /*
* fieldInitializations geloescht PL 2018-11-24
*/);
}
private Method generateStaticConstructor(String className, List<Statement> initializations, GenericDeclarationList classGenerics, Token offset) {
RefType classType = ClassOrInterface.generateTypeOfClass(reg.getName(className), classGenerics, offset);
ParameterList params = new ParameterList(new ArrayList<>(), offset);
Block block = new Block(new ArrayList<>(initializations), offset);
return new Method(Modifier.PUBLIC, className, classType, params, block, classGenerics, offset);
}
private RefType convertSuperType(Java17Parser.TypeTypeContext typeType) {
ClassOrInterfaceTypeContext supertypecontext = typeType.classOrInterfaceType();
if (supertypecontext != null && supertypecontext.DOT().size() > 0) {
@@ -503,13 +531,13 @@ public class SyntaxTreeGenerator {
if (Objects.isNull(header.refType())) {
retType = TypePlaceholder.fresh(header.getStart());
} else {
if (header.refType() instanceof ReftypeContext reftype) {
if (header.refType() instanceof RefType2Context reftype) {
retType = TypeGenerator.convert(reftype.typeType(), reg, generics);
} else {
retType = new Void(header.refType().getStart());
}
}
StatementGenerator stmtgen = new StatementGenerator(reg, localgenerics, fields, new HashMap<>());
StatementGenerator stmtgen = new StatementGenerator(superClass, compiler, reg, localgenerics, fields, new HashMap<>());
ParameterList paramlist = stmtgen.convert(header.formalParameters().formalParameterList());
MethodBodyContext body = methoddeclaration.methodBody();
Block block = null;
@@ -549,13 +577,13 @@ public class SyntaxTreeGenerator {
gtvDeclarations = new GenericDeclarationList(new ArrayList<>(), constructordeclaration.getStart());
}
RefTypeOrTPHOrWildcardOrGeneric retType = TypeGenerator.convertTypeName(name, constructordeclaration.getStart(), reg, localgenerics);
StatementGenerator stmtgen = new StatementGenerator(reg, localgenerics, fields, new HashMap<>());
StatementGenerator stmtgen = new StatementGenerator(superClass, compiler, reg, localgenerics, fields, new HashMap<>());
ParameterList paramlist = stmtgen.convert(constructordeclaration.formalParameters().formalParameterList());
Block block = stmtgen.convert(constructordeclaration.constructorBody, true);
return new Constructor(modifiers, name, retType, paramlist, block, gtvDeclarations, constructordeclaration.getStart());
}
private List<? extends Field> convert(Java17Parser.FieldDeclarationContext fieldDeclContext, int modifiers, GenericsRegistry generics) {
List<? extends Field> convert(Java17Parser.FieldDeclarationContext fieldDeclContext, int modifiers, GenericsRegistry generics) {
List<Field> ret = new ArrayList<>();
RefTypeOrTPHOrWildcardOrGeneric fieldType;
if (fieldDeclContext.typeType() != null) {
@@ -567,9 +595,9 @@ public class SyntaxTreeGenerator {
}
for (Java17Parser.VariableDeclaratorContext varDecl : fieldDeclContext.variableDeclarators().variableDeclarator()) {
String fieldName = varDecl.variableDeclaratorId().getText();
this.fields.put(fieldName, fieldType);
this.fields.put(fieldName, new FieldEntry(fieldName, fieldType, modifiers));
if (varDecl.variableInitializer() != null) {
initializeField(varDecl, fieldType, generics);
initializeField(varDecl, Modifier.isStatic(modifiers), fieldType, generics);
}
ret.add(new Field(fieldName, fieldType, modifiers, varDecl.getStart()));
}
@@ -581,9 +609,13 @@ public class SyntaxTreeGenerator {
}
// Initialize a field by creating implicit constructor.
private void initializeField(Java17Parser.VariableDeclaratorContext ctx, RefTypeOrTPHOrWildcardOrGeneric typeOfField, GenericsRegistry generics) {
StatementGenerator statementGenerator = new StatementGenerator(reg, generics, fields, new HashMap<>());
fieldInitializations.add(statementGenerator.generateFieldAssignment(ctx, typeOfField));
private void initializeField(Java17Parser.VariableDeclaratorContext ctx, boolean isStatic, RefTypeOrTPHOrWildcardOrGeneric typeOfField, GenericsRegistry generics) {
StatementGenerator statementGenerator = new StatementGenerator(superClass, compiler, reg, generics, fields, new HashMap<>());
var assignment = statementGenerator.generateFieldAssignment(ctx, typeOfField);
if (isStatic) {
staticFieldInitializations.add(assignment);
}
else fieldInitializations.add(assignment);
}
public int convertModifier(String modifier) {
@@ -65,6 +65,8 @@ public class TypeGenerator {
return new RefType(ASTFactory.createClass(Boolean.class).getClassName(), typeContext.getStart());
case "int":
return new RefType(ASTFactory.createClass(Integer.class).getClassName(), typeContext.getStart());
case "double":
return new RefType(ASTFactory.createClass(Double.class).getClassName(), typeContext.getStart());
default:
throw new NotImplementedException();
}
@@ -1,28 +1,48 @@
package de.dhbwstuttgart.parser.scope;
import java.util.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import org.antlr.v4.runtime.ParserRuleContext;
import de.dhbwstuttgart.parser.antlr.Java17Parser.ClassDeclarationContext;
import de.dhbwstuttgart.parser.antlr.Java17Parser.ClassorinterfacedeclContext;
import de.dhbwstuttgart.parser.antlr.Java17Parser.NoclassorinterfaceContext;
import de.dhbwstuttgart.parser.antlr.Java17Parser.SrcfileContext;
import com.google.common.collect.Iterables;
import de.dhbwstuttgart.core.JavaTXCompiler;
import de.dhbwstuttgart.environment.PackageCrawler;
import de.dhbwstuttgart.exceptions.NotImplementedException;
import de.dhbwstuttgart.parser.antlr.Java17Parser;
import de.dhbwstuttgart.parser.antlr.Java17Parser.AnnotationTypeElementDeclarationContext;
import de.dhbwstuttgart.parser.antlr.Java17Parser.ClassBodyContext;
import de.dhbwstuttgart.parser.antlr.Java17Parser.ClassBodyDeclarationContext;
import de.dhbwstuttgart.parser.antlr.Java17Parser.ClassOrInterfaceContext;
import de.dhbwstuttgart.parser.antlr.Java17Parser.ClassorinterfacedeclContext;
import de.dhbwstuttgart.parser.antlr.Java17Parser.EnumConstantContext;
import de.dhbwstuttgart.parser.antlr.Java17Parser.EnumConstantsContext;
import de.dhbwstuttgart.parser.antlr.Java17Parser.InterfaceBodyDeclarationContext;
import de.dhbwstuttgart.parser.antlr.Java17Parser.InterfacememberContext;
import de.dhbwstuttgart.parser.antlr.Java17Parser.MemberclassorinterfaceContext;
import de.dhbwstuttgart.parser.antlr.Java17Parser.MemberdeclContext;
import de.dhbwstuttgart.parser.antlr.Java17Parser.NoclassorinterfaceContext;
import de.dhbwstuttgart.parser.antlr.Java17Parser.SrcfileContext;
import de.dhbwstuttgart.parser.antlr.Java17Parser.SubclassorinterfaceContext;
public class GatherNames {
public static Map<String, Integer> getNames(SrcfileContext ctx, PackageCrawler packages, ClassLoader classLoader) throws ClassNotFoundException {
public static Map<String, Integer> getNames(SrcfileContext ctx, PackageCrawler packages, JavaTXCompiler compiler) throws ClassNotFoundException {
Map<String, Integer> ret = new HashMap<>();
String pkgName = getPackageName(ctx);
String nameString = "";
for (Java17Parser.ClassOrInterfaceContext member : ctx.classOrInterface()) {
if (member instanceof NoclassorinterfaceContext) {
for (Java17Parser.ClassOrInterfaceContext clsoifctx : ctx.classOrInterface()) {
if (clsoifctx instanceof NoclassorinterfaceContext) {
continue;
}
ClassorinterfacedeclContext clsoif = (ClassorinterfacedeclContext) member;
ret.putAll(getNames(clsoifctx, getPackageName(ctx), packages, compiler));
}
ret.putAll(getImports(ctx, packages, compiler));
return ret;
}
public static Map<String, Integer> getNames(ClassOrInterfaceContext clsoifctx, String pkgName, PackageCrawler packages, JavaTXCompiler compiler) throws ClassNotFoundException {
Map<String, Integer> ret = new HashMap<>();
ClassorinterfacedeclContext clsoif = (ClassorinterfacedeclContext) clsoifctx;
String nameString = "";
String fullname = clsoif.getChild(clsoif.getChildCount() - 1).getClass().getName();
String classname = fullname.substring(fullname.indexOf("$") + 1);
int numGenerics = 0;
@@ -38,6 +58,7 @@ public class GatherNames {
}
numGenerics = clsoif.classDeclaration().genericDeclarationList() != null ? clsoif.classDeclaration().genericDeclarationList().genericTypeVar().size() : 0;
ret.put(nameString, numGenerics);
ret.putAll(getNames(clsoif.classDeclaration().classBody().classBodyDeclaration(), pkgName, packages, compiler));
break;
case "EnumDeclarationContext":
if (!pkgName.isEmpty()) {
@@ -47,6 +68,15 @@ public class GatherNames {
}
numGenerics = 0;
ret.put(nameString, numGenerics);
EnumConstantsContext enumConstants = clsoif.enumDeclaration().enumConstants();
if (!Objects.isNull(enumConstants)) {
for (EnumConstantContext enumConstant : enumConstants.enumConstant()) {
ClassBodyContext enumConstClassBody = enumConstant.classBody();
if (!Objects.isNull(enumConstClassBody)) {
ret.putAll(getNames(enumConstClassBody.classBodyDeclaration(), pkgName, packages, compiler));
}
}
}
break;
case "InterfaceDeclarationContext":
if (pkgName != "") {
@@ -56,6 +86,11 @@ public class GatherNames {
}
numGenerics = clsoif.interfaceDeclaration().genericDeclarationList() != null ? clsoif.interfaceDeclaration().genericDeclarationList().genericTypeVar().size() : 0;
ret.put(nameString, numGenerics);
for (InterfaceBodyDeclarationContext ifbody : clsoif.interfaceDeclaration().interfaceBody().interfaceBodyDeclaration()) {
if (ifbody instanceof InterfacememberContext member && member.interfaceMemberDeclaration() instanceof SubclassorinterfaceContext sub) {
ret.putAll(getNames(sub.classOrInterface(), pkgName, packages, compiler));
}
}
break;
case "AnnotationTypeDeclarationContext":
if (pkgName != "") {
@@ -65,6 +100,12 @@ public class GatherNames {
}
numGenerics = 0;
ret.put(nameString, numGenerics);
for (AnnotationTypeElementDeclarationContext anTypeElem : clsoif.annotationTypeDeclaration().annotationTypeBody().annotationTypeElementDeclaration()) {
ClassOrInterfaceContext anClsoifctx = anTypeElem.annotationTypeElementRest().classOrInterface();
if (!Objects.isNull(anClsoifctx)) {
ret.putAll(getNames(anClsoifctx, pkgName, packages, compiler));
}
}
break;
case "RecordDeclarationContext":
if (pkgName != "") {
@@ -74,23 +115,39 @@ public class GatherNames {
}
numGenerics = clsoif.recordDeclaration().genericDeclarationList() != null ? clsoif.recordDeclaration().genericDeclarationList().genericTypeVar().size() : 0;
ret.put(nameString, numGenerics);
ret.putAll(getNames(clsoif.recordDeclaration().recordBody().classBodyDeclaration(), pkgName, packages, compiler));
break;
default:
throw new NotImplementedException();
}
}
ret.putAll(getImports(ctx, packages, classLoader));
return ret;
}
public static Map<String, Integer> getImports(Java17Parser.SrcfileContext ctx, PackageCrawler packages, ClassLoader classLoader) throws ClassNotFoundException {
public static Map<String, Integer> getNames(List<ClassBodyDeclarationContext> clsBodyDecl, String pkgName, PackageCrawler packages, JavaTXCompiler compiler) throws ClassNotFoundException {
Map<String, Integer> ret = new HashMap<>();
for (ClassBodyDeclarationContext clsbody : clsBodyDecl) {
if (clsbody instanceof MemberdeclContext member && member.memberDeclaration() instanceof MemberclassorinterfaceContext memberclsoifctx) {
ret.putAll(getNames(memberclsoifctx.classOrInterface(), pkgName, packages, compiler));
}
}
return ret;
}
public static Map<String, Integer> getImports(Java17Parser.SrcfileContext ctx, PackageCrawler packages, JavaTXCompiler compiler) throws ClassNotFoundException {
Map<String, Integer> ret = new HashMap<>();
// ret.putAll(packages.getClassNames("java.lang"));
for (Java17Parser.ImportDeclarationContext importDeclCtx : ctx.importDeclaration()) {
if (importDeclCtx.MUL() == null) {
Class<?> cl = classLoader.loadClass(importDeclCtx.qualifiedName().getText());
var name = importDeclCtx.qualifiedName().getText();
var className = new JavaClassName(name);
if (compiler.loadJavaTXClass(className)) {
ret.put(name, compiler.classRegistry.getNumberOfGenerics(name));
} else {
Class<?> cl = compiler.getClassLoader().loadClass(name);
ret.put(cl.getName(), cl.getTypeParameters().length);
}
} else if (importDeclCtx.MUL() != null) {
// TODO Find stuff in user defined packages
ret.putAll(packages.getClassNames(importDeclCtx.qualifiedName().getText()));
}
// Die Unterscheidungen für 'static imports' wurden herausgenommen, da sie den
@@ -12,6 +12,10 @@ import java.util.List;
*/
public class JavaClassName {
// FIXME It's very much possible to have imports to inner classes
// In that case a.package.Foo.Bar, a.package is the Package and Foo.Bar the class name
// Its impossible to decide what's the package based solely on the name of the class
public static final JavaClassName Void = new JavaClassName("void");
private String name;
private PackageName packageName;
@@ -11,9 +11,19 @@ public class JavaClassRegistry {
final Map<JavaClassName, Integer> existingClasses = new HashMap<>();
public JavaClassRegistry(Map<String, Integer> initialNames) {
for (String name : initialNames.keySet()) {
existingClasses.put(new JavaClassName(name), initialNames.get(name));
addNames(initialNames);
}
public JavaClassRegistry() {}
public void addNames(Map<String, Integer> names) {
for (String name : names.keySet()) {
existingClasses.put(new JavaClassName(name), names.get(name));
}
}
public void addName(String className, int numberOfGenerics) {
existingClasses.put(new JavaClassName(className), numberOfGenerics);
}
public JavaClassName getName(String className) {
@@ -31,4 +31,11 @@ public interface ASTVisitor extends StatementVisitor{
void visit(ExtendsWildcardType extendsWildcardType);
void visit(GenericRefType genericRefType);
void visit(ExpressionPattern aPattern);
void visit(RecordPattern aRecordPattern);
void visit(GuardedPattern aGuardedPattern);
}
@@ -2,10 +2,10 @@ package de.dhbwstuttgart.syntaxtree;
import de.dhbwstuttgart.parser.SyntaxTreeGenerator.AssignToLocal;
import de.dhbwstuttgart.syntaxtree.statement.*;
import de.dhbwstuttgart.syntaxtree.statement.Literal;
import de.dhbwstuttgart.syntaxtree.type.*;
import java.util.Iterator;
import java.util.Objects;
public abstract class AbstractASTWalker implements ASTVisitor {
@Override
@@ -66,7 +66,7 @@ public abstract class AbstractASTWalker implements ASTVisitor {
@Override
public void visit(ParameterList formalParameters) {
Iterator<FormalParameter> it = formalParameters.getFormalparalist().iterator();
Iterator<Pattern> it = formalParameters.getFormalparalist().iterator();
if (it.hasNext()) {
while (it.hasNext()) {
it.next().accept(this);
@@ -134,6 +134,11 @@ public abstract class AbstractASTWalker implements ASTVisitor {
}
@Override
public void visit(BoolExpression logical) {
}
@Override
public void visit(Block block) {
for (Statement stmt : block.getStatements()) {
@@ -158,12 +163,13 @@ public abstract class AbstractASTWalker implements ASTVisitor {
@Override
public void visit(ForStmt forStmt) {
forStmt.body_Loop_block.accept(this);
forStmt.block.accept(this);
}
@Override
public void visit(IfStmt ifStmt) {
ifStmt.then_block.accept(this);
if (!Objects.isNull(ifStmt.else_block))
ifStmt.else_block.accept(this);
}
@@ -269,4 +275,46 @@ public abstract class AbstractASTWalker implements ASTVisitor {
public void visit(SuperCall superCall) {
this.visit((MethodCall) superCall);
}
@Override
public void visit(Switch switchStmt) {
switchStmt.getSwitch().accept(this);
switchStmt.getBlocks().stream().forEach((switchBlock) -> {
switchBlock.accept(this);
});
}
@Override
public void visit(SwitchBlock switchBlock) {
switchBlock.getLabels().stream().forEach((label) -> {
label.accept(this);
});
switchBlock.getStatements().stream().forEach((stmt) -> {
stmt.accept(this);
});
}
@Override
public void visit(SwitchLabel switchLabel) {
}
@Override
public void visit(Yield aYield) {
}
@Override
public void visit(ExpressionPattern aPattern) {
}
@Override
public void visit(RecordPattern aRecordPattern) {
}
@Override
public void visit(GuardedPattern aGuardedPattern) {
}
}
@@ -1,18 +1,11 @@
package de.dhbwstuttgart.syntaxtree;
import de.dhbwstuttgart.core.IItemWithOffset;
import de.dhbwstuttgart.exceptions.DebugException;
import de.dhbwstuttgart.parser.NullToken;
import de.dhbwstuttgart.parser.scope.JavaClassName;
import de.dhbwstuttgart.syntaxtree.statement.Statement;
import de.dhbwstuttgart.syntaxtree.type.GenericRefType;
import de.dhbwstuttgart.syntaxtree.type.RefType;
import de.dhbwstuttgart.syntaxtree.type.TypePlaceholder;
import de.dhbwstuttgart.syntaxtree.visual.ASTPrinter;
import de.dhbwstuttgart.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric;
import de.dhbwstuttgart.typeinference.constraints.Constraint;
import de.dhbwstuttgart.typeinference.constraints.ConstraintSet;
import de.dhbwstuttgart.typeinference.assumptions.TypeInferenceInformation;
import org.antlr.v4.runtime.Token;
import java.lang.reflect.Modifier;
@@ -30,32 +23,38 @@ public class ClassOrInterface extends SyntaxTreeNode implements TypeScope{
protected JavaClassName name;
private List<Field> fields = new ArrayList<>();
private Optional<Constructor> fieldInitializations; // PL 2018-11-24: Noetig, um Bytecode fuer initializators nur einmal zu erzeugen
private Optional<Method> staticInitializer;
private List<Method> methods = new ArrayList<>();
private GenericDeclarationList genericClassParameters;
private RefType superClass;
protected boolean isInterface;
protected boolean isFunctionalInterface;
private List<RefType> implementedInterfaces;
private List<RefType> permittedSubtypes;
private List<Constructor> constructors;
public ClassOrInterface(int modifiers, JavaClassName name, List<Field> fielddecl, Optional<Constructor> fieldInitializations, List<Method> methods, List<Constructor> constructors, GenericDeclarationList genericClassParameters,
RefType superClass, Boolean isInterface, List<RefType> implementedInterfaces, Token offset){
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) {
super(offset);
if(isInterface && !Modifier.isInterface(modifiers))modifiers += Modifier.INTERFACE;
if (isInterface) {
modifiers |= Modifier.INTERFACE | Modifier.ABSTRACT;
}
this.modifiers = modifiers;
this.name = name;
this.fields = fielddecl;
this.fieldInitializations = fieldInitializations;
this.staticInitializer = staticInitializer;
this.genericClassParameters = genericClassParameters;
this.superClass = superClass;
this.isInterface = isInterface;
this.isFunctionalInterface= isFunctionalInterface;
this.implementedInterfaces = implementedInterfaces;
this.permittedSubtypes = permittedSubtypes;
this.methods = methods;
this.constructors = constructors;
}
/* erzeugt fuer Fields, Konstruktoren und Methoden neue ArrayList-Objekte
* alle anderen Datenobjekte werden nur kopiert.
/*
* erzeugt fuer Fields, Konstruktoren und Methoden neue ArrayList-Objekte alle anderen Datenobjekte werden nur kopiert.
*/
public ClassOrInterface(ClassOrInterface cl) {
super(cl.getOffset());
@@ -63,14 +62,33 @@ public class ClassOrInterface extends SyntaxTreeNode implements TypeScope{
this.name = cl.name;
this.fields = new ArrayList<>(cl.fields);
this.fieldInitializations = cl.fieldInitializations;
this.staticInitializer = cl.staticInitializer;
this.genericClassParameters = cl.genericClassParameters;
this.superClass = cl.superClass;
this.isInterface = cl.isInterface;
this.isFunctionalInterface= cl.isFunctionalInterface;
this.implementedInterfaces = cl.implementedInterfaces;
this.methods = new ArrayList<>(cl.methods);
this.constructors = new ArrayList<>(cl.constructors);
}
public Optional<Field> getField(String name) {
// TODO This should be a map
return fields.stream().filter(field -> field.getName().equals(name)).findFirst();
}
public Optional<Method> getStaticInitializer() {
return staticInitializer;
}
public boolean isInterface() {
return (Modifier.INTERFACE & this.getModifiers()) != 0;
}
public boolean isFunctionalInterface() {
return this.isFunctionalInterface;
}
// Gets if it is added
public Boolean areMethodsAdded() {
return methodAdded;
@@ -104,9 +122,7 @@ public class ClassOrInterface extends SyntaxTreeNode implements TypeScope{
}
/*
public RefType getType() {
return generateTypeOfClass(this.getClassName(), this.getGenerics(), this.getOffset());
}
* public RefType getType() { return generateTypeOfClass(this.getClassName(), this.getGenerics(), this.getOffset()); }
*/
// TODO: Das hier ist ein Problem. Je nach Kontext wird hier ein anderer Typ benötigt
public static RefType generateTypeOfClass(JavaClassName name, GenericDeclarationList genericsOfClass, Token offset) {
@@ -131,9 +147,9 @@ public class ClassOrInterface extends SyntaxTreeNode implements TypeScope{
}
return new RefType(name, params, new NullToken());
}
/**
* Die Superklasse im Kontext dieser ClassOrInterface
* Das bedeutet, dass generische Variablen als GenericRefTypes dargestellt sind
* Die Superklasse im Kontext dieser ClassOrInterface Das bedeutet, dass generische Variablen als GenericRefTypes dargestellt sind
*/
public RefType getSuperClass() {
return superClass;
@@ -164,4 +180,5 @@ public class ClassOrInterface extends SyntaxTreeNode implements TypeScope{
public String toString() {
return this.name.toString() + this.genericClassParameters.toString();
}
}
@@ -0,0 +1,28 @@
package de.dhbwstuttgart.syntaxtree;
import de.dhbwstuttgart.syntaxtree.statement.Expression;
import de.dhbwstuttgart.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric;
import org.antlr.v4.runtime.Token;
public class ExpressionPattern extends Pattern {
private final Expression expression;
public ExpressionPattern(Expression expression, Token offset) {
super(expression.getType(), offset);
this.expression = expression;
}
public Expression getExpression() {
return expression;
}
@Override
public void accept(ASTVisitor visitor) {
visitor.visit(this);
}
@Override
public ExpressionPattern withType(RefTypeOrTPHOrWildcardOrGeneric type) {
return new ExpressionPattern(expression, getOffset());
}
}
@@ -3,18 +3,12 @@ package de.dhbwstuttgart.syntaxtree;
import de.dhbwstuttgart.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric;
import org.antlr.v4.runtime.Token;
public class FormalParameter extends SyntaxTreeNode {
private RefTypeOrTPHOrWildcardOrGeneric type;
public class FormalParameter extends Pattern {
private String name;
public FormalParameter(String name, RefTypeOrTPHOrWildcardOrGeneric type, Token offset) {
super(offset);
super(type, offset);
this.name = name;
this.type = type;
}
public RefTypeOrTPHOrWildcardOrGeneric getType() {
return type;
}
public String getName() {
@@ -25,4 +19,9 @@ public class FormalParameter extends SyntaxTreeNode {
public void accept(ASTVisitor visitor) {
visitor.visit(this);
}
@Override
public FormalParameter withType(RefTypeOrTPHOrWildcardOrGeneric type) {
return new FormalParameter(name, type, getOffset());
}
}
@@ -0,0 +1,35 @@
package de.dhbwstuttgart.syntaxtree;
import de.dhbwstuttgart.syntaxtree.statement.Expression;
import de.dhbwstuttgart.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric;
import org.antlr.v4.runtime.Token;
public class GuardedPattern extends Pattern {
private final Expression condition;
private final Pattern nested;
public GuardedPattern(Expression condition, Pattern nested, Token offset) {
super(nested.getType(), offset);
this.condition = condition;
this.nested = nested;
}
public Expression getCondition() {
return condition;
}
public Pattern getNestedPattern() {
return nested;
}
@Override
public void accept(ASTVisitor visitor) {
visitor.visit(this);
}
@Override
public GuardedPattern withType(RefTypeOrTPHOrWildcardOrGeneric type) {
return new GuardedPattern(condition, nested, getOffset());
}
}
@@ -67,7 +67,7 @@ public class Method extends SyntaxTreeNode implements IItemWithOffset, TypeScope
return parameterlist;
}
public Iterable<? extends GenericTypeVar> getGenerics() {
public GenericDeclarationList getGenerics() {
return generics;
}
@@ -5,27 +5,27 @@ import org.antlr.v4.runtime.Token;
import java.util.Iterator;
import java.util.List;
public class ParameterList extends SyntaxTreeNode implements Iterable<FormalParameter> {
private List<FormalParameter> formalparameter;
public class ParameterList extends SyntaxTreeNode implements Iterable<Pattern> {
private List<Pattern> formalparameter;
public ParameterList(List<FormalParameter> params, Token offset) {
public ParameterList(List<Pattern> params, Token offset) {
super(offset);
this.formalparameter = params;
}
public FormalParameter getParameterAt(int i) {
public Pattern getParameterAt(int i) {
if (i >= formalparameter.size())
return null;
return formalparameter.get(i);
}
public List<FormalParameter> getFormalparalist() {
public List<Pattern> getFormalparalist() {
return formalparameter;
}
@Override
public Iterator<FormalParameter> iterator() {
public Iterator<Pattern> iterator() {
return formalparameter.iterator();
}
@@ -0,0 +1,19 @@
package de.dhbwstuttgart.syntaxtree;
import de.dhbwstuttgart.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric;
import org.antlr.v4.runtime.Token;
public abstract class Pattern extends SyntaxTreeNode {
private final RefTypeOrTPHOrWildcardOrGeneric type;
public Pattern(RefTypeOrTPHOrWildcardOrGeneric type, Token offset) {
super(offset);
this.type = type;
}
public RefTypeOrTPHOrWildcardOrGeneric getType(){
return type;
}
public abstract Pattern withType(RefTypeOrTPHOrWildcardOrGeneric type);
}
@@ -1,5 +1,6 @@
package de.dhbwstuttgart.syntaxtree;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
@@ -8,9 +9,11 @@ import org.antlr.v4.runtime.Token;
import de.dhbwstuttgart.parser.scope.JavaClassName;
import de.dhbwstuttgart.syntaxtree.type.RefType;
import javax.swing.text.html.Option;
public class Record extends ClassOrInterface {
public Record(int modifiers, JavaClassName name, List<Field> fielddecl, Optional<Constructor> fieldInitializations, List<Method> methods, List<Constructor> constructors, GenericDeclarationList genericClassParameters, RefType superClass, Boolean isInterface, List<RefType> implementedInterfaces, Token offset) {
super(modifiers, name, fielddecl, fieldInitializations, methods, constructors, genericClassParameters, superClass, isInterface, implementedInterfaces, offset);
public Record(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, List<RefType> implementedInterfaces, Token offset) {
super(modifiers, name, fielddecl, fieldInitializations, staticInitializer, methods, constructors, genericClassParameters, superClass, isInterface, methods.size() == 1 ? true : false, implementedInterfaces, new ArrayList<>(), offset);
}
}
@@ -0,0 +1,33 @@
package de.dhbwstuttgart.syntaxtree;
import java.util.ArrayList;
import java.util.List;
import org.antlr.v4.runtime.Token;
import de.dhbwstuttgart.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric;
public class RecordPattern extends FormalParameter {
private final List<Pattern> subPattern;
public RecordPattern(String name, RefTypeOrTPHOrWildcardOrGeneric type, Token offset) {
super(name, type, offset);
subPattern = new ArrayList<>();
}
public RecordPattern(List<Pattern> subPattern, String name, RefTypeOrTPHOrWildcardOrGeneric type, Token offset) {
super(name, type, offset);
this.subPattern = subPattern;
}
public List<Pattern> getSubPattern() {
return this.subPattern;
}
@Override
public void accept(ASTVisitor visitor) {
visitor.visit(this);
}
}
@@ -21,11 +21,11 @@ public class SourceFile extends SyntaxTreeNode {
*/
public SourceFile(String pkgName, List<ClassOrInterface> classDefinitions, Set<JavaClassName> imports) {
super(new NullToken());
if (classDefinitions.size() > 0) { // Enthält die Liste Klassen?
//if (classDefinitions.size() > 0) { // Enthält die Liste Klassen?
this.KlassenVektor = classDefinitions; // Klassen werden übernommen
} else {
this.KlassenVektor = null; // es handelt sich um ein "Java Module"
}
//} else {
// this.KlassenVektor = null; // es handelt sich um ein "Java Module"
//}
this.pkgName = pkgName;
this.imports = imports;
}
@@ -13,6 +13,8 @@ public interface StatementVisitor {
void visit(BinaryExpr binary);
void visit(BoolExpression logical);
void visit(Block block);
void visit(CastExpr castExpr);
@@ -41,8 +43,16 @@ public interface StatementVisitor {
void visit(ReturnVoid aReturn);
void visit(Switch switchStmt);
void visit(SwitchBlock switchBlock);
void visit(SwitchLabel switchLabel);
void visit(Break aBreak);
void visit(Yield aYield);
void visit(StaticClassName staticClassName);
void visit(Super aSuper);
@@ -1,27 +1,25 @@
package de.dhbwstuttgart.syntaxtree.factory;
import java.io.File;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.Type;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
import de.dhbwstuttgart.bytecode.JavaTXSignatureAttribute;
import de.dhbwstuttgart.parser.NullToken;
import de.dhbwstuttgart.parser.scope.JavaClassName;
import de.dhbwstuttgart.syntaxtree.*;
import de.dhbwstuttgart.syntaxtree.Field;
import de.dhbwstuttgart.syntaxtree.Method;
import de.dhbwstuttgart.syntaxtree.type.*;
import de.dhbwstuttgart.syntaxtree.type.Void;
import de.dhbwstuttgart.syntaxtree.*;
import de.dhbwstuttgart.syntaxtree.statement.Block;
import de.dhbwstuttgart.syntaxtree.statement.Statement;
import de.dhbwstuttgart.syntaxtree.type.WildcardType;
import de.dhbwstuttgart.target.tree.type.TargetRefType;
import de.dhbwstuttgart.util.Pair;
import javassist.bytecode.SignatureAttribute;
import org.antlr.v4.runtime.Token;
import org.apache.commons.io.IOUtils;
import org.objectweb.asm.*;
@@ -29,13 +27,15 @@ import org.objectweb.asm.signature.SignatureReader;
import org.objectweb.asm.signature.SignatureVisitor;
/**
* Anmerkung:
* Die ASTFactory Methoden, welche ASTBäume aus java.lang.Class Objekten generieren, können davon ausgehen,
* dass alle Imports und Typnamen korrekt sind und müssen diese nicht überprüfen.
* Anmerkung: Die ASTFactory Methoden, welche ASTBäume aus java.lang.Class Objekten generieren, können davon ausgehen, dass alle Imports und Typnamen korrekt sind und müssen diese nicht überprüfen.
*/
public class ASTFactory {
private static final HashMap<java.lang.Class, ClassOrInterface> cache = new HashMap<>();
public static ClassOrInterface createClass(java.lang.Class jreClass) {
if (cache.containsKey(jreClass))
return cache.get(jreClass);
// TODO Inner classes
@@ -46,7 +46,7 @@ public class ASTFactory {
try {
var path = jreClass.getName().replace('.', '/') + ".class";
var classLoader = jreClass.getClassLoader();
if (classLoader != null) {
if (classLoader != null && new File(path).exists()) {
var bytes = IOUtils.toByteArray(Objects.requireNonNull(classLoader.getResourceAsStream(path)));
var classReader = new ClassReader(bytes);
var classVisitor = new ClassVisitor(Opcodes.ASM7) {
@@ -88,7 +88,6 @@ public class ASTFactory {
} catch (IOException e) {
// Skip
}
JavaClassName name = new JavaClassName(jreClass.getName());
List<Method> methoden = new ArrayList<>();
List<de.dhbwstuttgart.syntaxtree.Constructor> konstruktoren = new ArrayList<>();
@@ -114,6 +113,12 @@ public class ASTFactory {
}
int modifier = jreClass.getModifiers();
boolean isInterface = jreClass.isInterface();
List<Annotation> aLA;
boolean isFunctionalInterface =
(aLA = Arrays.asList(jreClass.getAnnotations())).size() > 0 &&
aLA.get(0) instanceof FunctionalInterface ?
true :
false;
// see: https://stackoverflow.com/questions/9934774/getting-generic-parameter-from-supertype-class
ParameterizedType parameterSuperClass = null;
Type tempSuperClass = jreClass.getGenericSuperclass();
@@ -132,12 +137,20 @@ public class ASTFactory {
for (Type jreInterface : jreClass.getGenericInterfaces()) {
implementedInterfaces.add((RefType) createType(jreInterface));
}
List<RefType> permittedSubtypes = new ArrayList<>();
if (jreClass.isSealed()) {
for (Class subclass : jreClass.getPermittedSubclasses()) {
permittedSubtypes.add((RefType) createType(subclass));
}
}
GenericDeclarationList genericDeclarationList = createGenerics(jreClass.getTypeParameters(), jreClass, null, classSignature);
Token offset = new NullToken(); // Braucht keinen Offset, da diese Klasse nicht aus einem Quellcode geparst wurde
return new ClassOrInterface(modifier, name, felder, Optional.empty() /* eingefuegt PL 2018-11-24 */,methoden, konstruktoren, genericDeclarationList, superClass,isInterface, implementedInterfaces, offset);
var cinf = new ClassOrInterface(modifier, name, felder, Optional.empty() /* eingefuegt PL 2018-11-24 */, Optional.empty(), methoden, konstruktoren, genericDeclarationList, superClass, isInterface, isFunctionalInterface, implementedInterfaces, permittedSubtypes, offset);
cache.put(jreClass, cinf);
return cinf;
}
private static Field createField(java.lang.reflect.Field field, JavaClassName jreClass) {
@@ -153,10 +166,11 @@ public class ASTFactory {
RefTypeOrTPHOrWildcardOrGeneric returnType = createType(inClass);
Parameter[] jreParams = constructor.getParameters();
Type[] jreGenericParams = constructor.getGenericParameterTypes();
List<FormalParameter> params = new ArrayList<>();
List<Pattern> params = new ArrayList<>();
int i = 0;
for (Type jreParam : jreGenericParams) {
if (jreParam == null) continue;
if (jreParam == null)
continue;
RefTypeOrTPHOrWildcardOrGeneric paramType = createType(jreParam);
params.add(new FormalParameter(jreParams[i].getName(), paramType, new NullToken()));
i++;
@@ -186,10 +200,11 @@ public class ASTFactory {
returnType = createType(jreRetType);
Parameter[] jreParams = jreMethod.getParameters();
Type[] jreGenericParams = jreMethod.getGenericParameterTypes();
List<FormalParameter> params = new ArrayList<>();
List<Pattern> params = new ArrayList<>();
int i = 0;
for (Type jreParam : jreGenericParams) {
if (jreParam == null) continue;
if (jreParam == null)
continue;
RefTypeOrTPHOrWildcardOrGeneric paramType = createType(jreParam);
params.add(new FormalParameter(jreParams[i].getName(), paramType, new NullToken()));
i++;
@@ -217,7 +232,8 @@ public class ASTFactory {
}
public static GenericDeclarationList createGenerics(String signature) {
if (signature == null) return new GenericDeclarationList(new ArrayList<>(), new NullToken());
if (signature == null)
return new GenericDeclarationList(new ArrayList<>(), new NullToken());
var gtvs = new ArrayList<GenericTypeVar>();
var signatureVisitor = new SignatureVisitor(Opcodes.ASM7) {
@@ -226,7 +242,8 @@ public class ASTFactory {
final Stack<RefType> classTypes = new Stack<>();
// All hail the mighty visitor pattern
final SignatureVisitor doNothing = new SignatureVisitor(Opcodes.ASM7) {};
final SignatureVisitor doNothing = new SignatureVisitor(Opcodes.ASM7) {
};
char wildcard = '=';
@@ -338,19 +355,19 @@ public class ASTFactory {
if (type == null || type.getTypeName().equals("void")) {
return new Void(new NullToken());
} else if (type.getTypeName().equals("int")) {
return new RefType(new JavaClassName("java.lang.Integer"), new ArrayList<>(), new NullToken());
return new RefType(new JavaClassName("java.lang.Integer"), new ArrayList<>(), new NullToken(), true);
} else if (type.getTypeName().equals("byte")) {
return new RefType(new JavaClassName("java.lang.Byte"), new ArrayList<>(), new NullToken());
return new RefType(new JavaClassName("java.lang.Byte"), new ArrayList<>(), new NullToken(), true);
} else if (type.getTypeName().equals("boolean")) {
return new RefType(new JavaClassName("java.lang.Boolean"), new ArrayList<>(), new NullToken());
return new RefType(new JavaClassName("java.lang.Boolean"), new ArrayList<>(), new NullToken(), true);
} else if (type.getTypeName().equals("char")) {
return new RefType(new JavaClassName("java.lang.Char"), new ArrayList<>(), new NullToken());
return new RefType(new JavaClassName("java.lang.Char"), new ArrayList<>(), new NullToken(), true);
} else if (type.getTypeName().equals("short")) {
return new RefType(new JavaClassName("java.lang.Short"), new ArrayList<>(), new NullToken());
return new RefType(new JavaClassName("java.lang.Short"), new ArrayList<>(), new NullToken(), true);
} else if (type.getTypeName().equals("double")) {
return new RefType(new JavaClassName("java.lang.Double"), new ArrayList<>(), new NullToken());
return new RefType(new JavaClassName("java.lang.Double"), new ArrayList<>(), new NullToken(), true);
} else if (type.getTypeName().equals("long")) {
return new RefType(new JavaClassName("java.lang.Long"), new ArrayList<>(), new NullToken());
return new RefType(new JavaClassName("java.lang.Long"), new ArrayList<>(), new NullToken(), true);
} else {
if (type instanceof TypeVariable) {
// GTVDeclarationContext via "(TypeVariable) type).getGenericDeclaration()"
@@ -404,48 +421,26 @@ public class ASTFactory {
}
/*
public Constructor createEmptyConstructor(Class parent){
Block block = new Block();
block.setType(new de.dhbwstuttgart.syntaxtree.type.Void(block, 0));
block.statements.add(new SuperCall(block));
return ASTFactory.createConstructor(parent, new ParameterList(), block);
}
public static Constructor createConstructor(Class superClass, ParameterList paralist, Block block){
block.parserPostProcessing(superClass);
Method method = ASTFactory.createMethod("<init>", paralist, block, superClass);
method.setType(new de.dhbwstuttgart.syntaxtree.type.Void(block, 0));
return new Constructor(method, superClass);
}
public static Class createClass(String className, RefType type, Modifiers modifiers, Menge supertypeGenPara, SourceFile parent) {
// TODO bytecode createClass
//String name, RefType superClass, Modifiers modifiers, Menge<String> supertypeGenPara
Class generatedClass = new Class(className, type, modifiers, supertypeGenPara);
generatedClass.addField(ASTFactory.createEmptyConstructor(generatedClass));
generatedClass.parserPostProcessing(parent);
return generatedClass;
}
public static Class createObject(){
return createClass(java.lang.Object.class);
}
public static Class createInterface(String className, RefType superClass, Modifiers modifiers,
Menge supertypeGenPara, SourceFile parent){
Class generatedClass = new Class(new JavaClassName(className), new ArrayList<Method>(), new ArrayList<Field>(), modifiers,
true, superClass, new ArrayList<RefType>(), new GenericDeclarationList(), -1);
generatedClass.parserPostProcessing(parent);
return generatedClass;
}
public static RefType createObjectType(){
return createObjectClass().getType();
}
* public Constructor createEmptyConstructor(Class parent){ Block block = new Block(); block.setType(new de.dhbwstuttgart.syntaxtree.type.Void(block, 0)); block.statements.add(new SuperCall(block));
*
* return ASTFactory.createConstructor(parent, new ParameterList(), block); }
*
* public static Constructor createConstructor(Class superClass, ParameterList paralist, Block block){ block.parserPostProcessing(superClass);
*
* Method method = ASTFactory.createMethod("<init>", paralist, block, superClass); method.setType(new de.dhbwstuttgart.syntaxtree.type.Void(block, 0));
*
* return new Constructor(method, superClass); }
*
* public static Class createClass(String className, RefType type, Modifiers modifiers, Menge supertypeGenPara, SourceFile parent) { // TODO bytecode createClass //String name, RefType superClass, Modifiers modifiers, Menge<String> supertypeGenPara Class generatedClass = new Class(className, type, modifiers, supertypeGenPara); generatedClass.addField(ASTFactory.createEmptyConstructor(generatedClass));
*
* generatedClass.parserPostProcessing(parent);
*
* return generatedClass; }
*
* public static Class createObject(){ return createClass(java.lang.Object.class); }
*
* public static Class createInterface(String className, RefType superClass, Modifiers modifiers, Menge supertypeGenPara, SourceFile parent){ Class generatedClass = new Class(new JavaClassName(className), new ArrayList<Method>(), new ArrayList<Field>(), modifiers, true, superClass, new ArrayList<RefType>(), new GenericDeclarationList(), -1); generatedClass.parserPostProcessing(parent); return generatedClass; }
*
* public static RefType createObjectType(){ return createObjectClass().getType(); }
*/
}
@@ -15,8 +15,8 @@ public class BinaryExpr extends Expression {
SUB, // -
MUL, // *
MOD, // Modulo Operator %
AND, // &&
OR, // ||
AND, // &
OR, // |
DIV, // /
LESSTHAN, // <
BIGGERTHAN, // >
@@ -1,26 +1,22 @@
package de.dhbwstuttgart.syntaxtree.statement;
import java.util.*;
import java.util.ArrayList;
import java.util.List;
import org.antlr.v4.runtime.Token;
import de.dhbwstuttgart.syntaxtree.StatementVisitor;
import de.dhbwstuttgart.syntaxtree.type.TypePlaceholder;
import de.dhbwstuttgart.typeinference.assumptions.TypeInferenceBlockInformation;
import de.dhbwstuttgart.typeinference.constraints.ConstraintSet;
import org.antlr.v4.runtime.Token;
public class Block extends Statement
{
public class Block extends Statement {
public Block(List<Statement> statements, Token offset) {
super(TypePlaceholder.fresh(offset), offset);
this.statements = statements;
}
public List<Statement> statements = new ArrayList<>();
public List<Statement> getStatements()
{
public List<Statement> getStatements() {
return statements;
}
@@ -29,5 +25,3 @@ public class Block extends Statement
visitor.visit(this);
}
}
@@ -0,0 +1,31 @@
package de.dhbwstuttgart.syntaxtree.statement;
import org.antlr.v4.runtime.Token;
import de.dhbwstuttgart.syntaxtree.StatementVisitor;
import de.dhbwstuttgart.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric;
public class BoolExpression extends Expression {
public enum Operator {
AND, // &&
OR, // ||
}
public final Operator operation;
public final Expression lexpr;
public final Expression rexpr;
public BoolExpression(Operator operation, RefTypeOrTPHOrWildcardOrGeneric type, Expression lexpr, Expression rexpr, Token offset) {
super(type, offset);
this.operation = operation;
this.lexpr = lexpr;
this.rexpr = rexpr;
}
@Override
public void accept(StatementVisitor visitor) {
visitor.visit(this);
}
}
@@ -13,7 +13,7 @@ public class Break extends Statement {
@Override
public void accept(StatementVisitor visitor) {
this.accept((StatementVisitor) visitor);
visitor.visit(this);
}
}
@@ -9,8 +9,7 @@ import de.dhbwstuttgart.typeinference.assumptions.TypeInferenceBlockInformation;
import de.dhbwstuttgart.typeinference.constraints.ConstraintSet;
import org.antlr.v4.runtime.Token;
public abstract class Expression extends TypableStatement
{
public abstract class Expression extends TypableStatement {
public Expression(RefTypeOrTPHOrWildcardOrGeneric type, Token offset) {
super(type, offset);
}

Some files were not shown because too many files have changed in this diff Show More