Compare commits

...

9 Commits

Author SHA1 Message Date
Ruben
c9d38728af set Target to 24
All checks were successful
Build and Test with Maven / Build-and-test-with-Maven (push) Successful in 2m40s
2025-09-18 18:02:45 +02:00
Ruben
b7fad6e3c7 delete LanguageServerInterfaceTest.java
Some checks failed
Build and Test with Maven / Build-and-test-with-Maven (push) Failing after 30s
2025-09-18 18:00:37 +02:00
Ruben
3cb9b74df1 clean up interface
Some checks failed
Build and Test with Maven / Build-and-test-with-Maven (push) Failing after 31s
2025-09-18 17:49:28 +02:00
Ruben
effc31782f Merge remote-tracking branch 'origin/LSP-Interface' into LSP-Interface
Some checks failed
Build and Test with Maven / Build-and-test-with-Maven (push) Failing after 32s
2025-09-18 17:42:49 +02:00
Ruben
2a24eab9d3 Merge branch 'refs/heads/master' into LSP-Interface 2025-09-18 17:33:36 +02:00
pl@gohorb.ba-horb.de
b29eb71238 Merge branch 'master' of https://gitea.hb.dhbw-stuttgart.de/JavaTX/JavaCompilerCore
All checks were successful
SonarQube Scan / SonarQube Trigger (push) Successful in 3m40s
2025-09-18 16:43:46 +02:00
pl@gohorb.ba-horb.de
e9ce071e2b modified: src/main/java/de/dhbwstuttgart/parser/SyntaxTreeGenerator/StatementGenerator.java
Die Parameter von Lambda-Ausdruecken wurden mit der Variance 1 belegt.
2025-09-18 16:39:12 +02:00
3567bae0d7 Decouple Generics from ASTToTargetAST
All checks were successful
SonarQube Scan / SonarQube Trigger (push) Successful in 3m16s
2025-09-17 17:19:23 +02:00
Ruben
a314013f40 feat: move compilation part into Language Server Interface
Some checks failed
Build and Test with Maven / Build-and-test-with-Maven (push) Failing after 32s
2025-09-17 11:30:35 +02:00
14 changed files with 112 additions and 296 deletions

View File

@@ -73,8 +73,8 @@ http://maven.apache.org/maven-v4_0_0.xsd">
<version>3.14.0</version> <version>3.14.0</version>
<configuration> <configuration>
<compilerArgs>--enable-preview</compilerArgs> <compilerArgs>--enable-preview</compilerArgs>
<source>23</source> <source>24</source>
<target>23</target> <target>24</target>
</configuration> </configuration>
</plugin> </plugin>
<plugin> <plugin>

View File

@@ -1778,7 +1778,7 @@ public class Codegen {
cw2.visitEnd(); cw2.visitEnd();
var bytes = cw2.toByteArray(); var bytes = cw2.toByteArray();
converter.auxiliaries.put(className, bytes); compiler.auxiliaries.put(className, bytes);
// TODO These class loading shenanigans happen in a few places, the tests load the classes individually. // TODO These class loading shenanigans happen in a few places, the tests load the classes individually.
// Instead we should just look at the folder. // Instead we should just look at the folder.

View File

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

View File

@@ -5,6 +5,7 @@ import de.dhbwstuttgart.bytecode.Codegen;
import de.dhbwstuttgart.core.JavaTXCompiler; import de.dhbwstuttgart.core.JavaTXCompiler;
import de.dhbwstuttgart.environment.IByteArrayClassLoader; import de.dhbwstuttgart.environment.IByteArrayClassLoader;
import de.dhbwstuttgart.languageServerInterface.model.LanguageServerTransferObject; import de.dhbwstuttgart.languageServerInterface.model.LanguageServerTransferObject;
import de.dhbwstuttgart.parser.scope.JavaClassName;
import de.dhbwstuttgart.syntaxtree.SourceFile; import de.dhbwstuttgart.syntaxtree.SourceFile;
import de.dhbwstuttgart.syntaxtree.factory.NameGenerator; import de.dhbwstuttgart.syntaxtree.factory.NameGenerator;
import de.dhbwstuttgart.target.generate.ASTToTargetAST; import de.dhbwstuttgart.target.generate.ASTToTargetAST;
@@ -47,59 +48,28 @@ public class LanguageServerInterface {
* You have to give the input as well as the path because of potential locks when the File is currently opened in an IDE. * You have to give the input as well as the path because of potential locks when the File is currently opened in an IDE.
* Example: file:///c:/test/main.jav -> file:///c:/test/out/main.class * Example: file:///c:/test/main.jav -> file:///c:/test/out/main.class
* *
* @param path the URI of the File. See Example. * @param pathAsString the URI of the File. See Example.
* @throws IOException * @throws IOException
* @throws ClassNotFoundException * @throws ClassNotFoundException
* @throws URISyntaxException * @throws URISyntaxException
*/ */
public LanguageServerTransferObject getResultSetAndAbstractSyntax(String path) throws IOException, ClassNotFoundException, URISyntaxException { public LanguageServerTransferObject getResultSetAndAbstractSyntax(String pathAsString) throws IOException, ClassNotFoundException, URISyntaxException {
System.setOut(new PrintStream(OutputStream.nullOutputStream()));
// var uri = new URI(pathAsString);
// System.setOut(new PrintStream(OutputStream.nullOutputStream())); var path = Path.of(uri);
// var file = path.toFile();
// Files.createDirectories(path.getParent().resolve("out"));
// URI uri = new URI(path); var compiler = new JavaTXCompiler(List.of(file), List.of(path.getParent().toFile()), path.getParent().resolve("out").toFile());
// ArrayList<String> pathWithoutName = new ArrayList<>(List.of(uri.getPath().split("/")));
// pathWithoutName.remove(List.of(uri.getPath().split("/")).size() - 1);
// String stringPathWithoutName = "";
//
// for (String i : pathWithoutName) {
// stringPathWithoutName += "/" + i;
// }
//
// try {
// FileUtils.cleanDirectory(new File(stringPathWithoutName + "/out"));
// } catch (Exception e) {
//
// }
// try {
// (new File(stringPathWithoutName + "/out")).mkdirs();
// } catch (Exception e) {
//
// }
// var test = getLanguageServerTransferObject(uri.getPath().split("/")[uri.getPath().split("/").length - 1], new ByteArrayClassLoader(), new File(stringPathWithoutName).getPath());
// System.setOut(System.out);
// return test;
// File oldTempSourcefile = new File(stringPathWithoutName + "/out/" + uri.getPath().split("/")[uri.getPath().split("/").length - 1].replace(".jav", ".tmp"));
// File oldTempOutFile = new File(stringPathWithoutName + "/out/" + uri.getPath().split("/")[uri.getPath().split("/").length - 1].replace(".jav", ".class"));
// Files.deleteIfExists(oldTempSourcefile.toPath());
// Files.deleteIfExists(oldTempOutFile.toPath());
// FileUtils.deleteDirectory(oldTempSourcefile);
//
// File tempSourcefile = new File(stringPathWithoutName + "/out/" + uri.getPath().split("/")[uri.getPath().split("/").length - 1].replace(".jav", ".tmp"));
// File tempOutFile = new File(stringPathWithoutName + "/out/");
// FileUtils.writeStringToFile(tempSourcefile, input, "UTF-8");
//
// //TODO: Enable for multiple Class-Files
// JavaTXCompiler tx = new JavaTXCompiler(new ArrayList<File>(List.of(tempSourcefile)), new ArrayList<File>(List.of((tempSourcefile))), tempOutFile);
// var result = tx.getResultSetAndAbstractSyntax(tempSourcefile);
// System.setOut(System.out);
// tempSourcefile.delete();
// tempOutFile.delete();
// return result;
var parsedSource = compiler.sourceFiles.get(file);
var tiResults = compiler.typeInference(file);
return null; Map<JavaClassName, byte[]> bytecode = compiler.generateBytecode(parsedSource, tiResults);
Files.createDirectories(path.getParent().resolve("out"));
compiler.writeClassFile(bytecode, path.getParent().resolve("out").toFile(), false);
return new LanguageServerTransferObject(tiResults, parsedSource, "", compiler.getGeneratedGenerics());
} }
/** /**
@@ -142,138 +112,9 @@ public class LanguageServerInterface {
return test; return test;
} }
private static void writeClassFile(String name, byte[] code, Path outputPath) throws IOException {
Files.createDirectories(outputPath);
Files.write(outputPath.resolve(name + ".class"), code);
}
public static Map<String, ? extends Class<?>> generateClassFiles(IByteArrayClassLoader classLoader, Path path, Path outputPath, String... files) throws IOException, ClassNotFoundException {
Files.createDirectories(outputPath);
var filenames = Arrays.stream(files).map(filename -> Path.of(path.toString(), filename).toFile()).toList();
var compiler = new JavaTXCompiler(filenames, List.of(path.toFile(), outputPath.toFile()), outputPath.toFile());
var result = new HashMap<String, Class<?>>();
for (var file : filenames) {
var resultSet = compiler.typeInference(file);
var sourceFile = compiler.sourceFiles.get(file);
var converter = new ASTToTargetAST(compiler, resultSet, sourceFile, classLoader);
var classes = compiler.sourceFiles.get(file).getClasses();
result.putAll(classes.stream().map(cli -> {
try {
return generateClass(converter.convert(cli), classLoader, converter, outputPath);
} catch (IOException exception) {
throw new RuntimeException(exception);
}
}).collect(Collectors.toMap(Class::getName, Function.identity())));
converter.generateFunNTypes();
for (var entry : converter.auxiliaries.entrySet()) {
writeClassFile(entry.getKey(), entry.getValue(), outputPath);
}
}
for (var entry : compiler.loadedClasses.entrySet()) {
var name = entry.getKey().toString();
result.put(name, classLoader.loadClass(Path.of(entry.getValue().classFile().toURI())));
}
return result;
}
public static Class<?> generateClass(TargetStructure clazz, IByteArrayClassLoader classLoader, ASTToTargetAST converter, Path outputPath) throws IOException {
Codegen codegen = new Codegen(clazz, converter.compiler, converter);
var code = codegen.generate();
writeClassFile(clazz.qualifiedName().getClassName(), code, outputPath);
return classLoader.loadClass(code);
}
public static Map<String, ? extends Class<?>> generateClassFiles(String filename, IByteArrayClassLoader classLoader, String filePath) throws IOException, ClassNotFoundException {
var file = Path.of(filePath, filename).toFile();
var compiler = new JavaTXCompiler(List.of(file), List.of(file.getParentFile()), Path.of(filePath + "/out").toFile());
var resultSet = compiler.typeInference(file);
var sourceFile = compiler.sourceFiles.get(file);
var converter = new ASTToTargetAST(compiler, resultSet, sourceFile, classLoader);
var classes = compiler.sourceFiles.get(file).getClasses();
var result = classes.stream().map(cli -> {
try {
return generateClass(converter.convert(cli), classLoader, converter, Path.of(filePath + "/out/"));
} catch (IOException exception) {
throw new RuntimeException(exception);
}
}).collect(Collectors.toMap(Class::getName, Function.identity()));
converter.generateFunNTypes();
for (var entry : converter.auxiliaries.entrySet()) {
writeClassFile(entry.getKey(), entry.getValue(), Path.of(filePath + "/out/"));
}
return result;
}
public static SourceFile getAST(String filename, String filePath) throws IOException, ClassNotFoundException { public static SourceFile getAST(String filename, String filePath) throws IOException, ClassNotFoundException {
var file = Path.of(filePath, filename).toFile(); var file = Path.of(filePath, filename).toFile();
var compiler = new JavaTXCompiler(List.of(file), List.of(file.getParentFile()), Path.of(filePath + "/out").toFile()); var compiler = new JavaTXCompiler(List.of(file), List.of(file.getParentFile()), Path.of(filePath + "/out").toFile());
return compiler.sourceFiles.get(file); return compiler.sourceFiles.get(file);
} }
public static LanguageServerTransferObject getLanguageServerTransferObject(String filename, IByteArrayClassLoader classLoader, String filePath) throws IOException, ClassNotFoundException {
var file = Path.of(filePath, filename).toFile();
var compiler = new JavaTXCompiler(List.of(file), List.of(file.getParentFile()), Path.of(filePath + "/out").toFile());
var resultSet = compiler.typeInference(file);
var sourceFile = compiler.sourceFiles.get(file);
var converter = new ASTToTargetAST(compiler, resultSet, sourceFile, classLoader);
compiler.generateBytecode();
converter.generateFunNTypes();
var ta = converter.javaGenerics();
var tb = converter.txGenerics();
Map<SourceFile, List<GenericsResult>> generics = new HashMap<>();
ArrayList<GenericsResult> genericsResults = new ArrayList<>();
genericsResults.addAll(ta);
genericsResults.addAll(tb);
generics.put(converter.compiler.sourceFiles.values().stream().findFirst().get(), ta);
var test = new LanguageServerTransferObject(resultSet, converter.compiler.sourceFiles.values().stream().findFirst().get(), "", compiler.getGeneratedGenerics());
return test;
}
/**
* generates Bytecode for the given Path of the File.
* The Generated Bytecode can be found in the same place as the path, except the File lies in an /out/ Directory
* Example: file:///c:/test/main.jav -> file:///c:/test/out/main.class
*
* @param uri the URI of the File. See Example.
* @throws IOException
* @throws ClassNotFoundException
* @throws URISyntaxException
*/
public void generateBytecode(URI uri) throws IOException, ClassNotFoundException, URISyntaxException {
// System.setOut(new PrintStream(OutputStream.nullOutputStream()));
//
//
// File inputDir = new File(uri.getPath());
// File outFile = new File(uri.getPath() + "/out");
// FileUtils.cleanDirectory(outFile);
// String[] allowedEndings = {".jav"};
// ArrayList<File> files = new ArrayList<>();
//
// try (Stream<Path> stream = Files.walk(Paths.get(inputDir.toURI()))) {
// stream.filter(Files::isRegularFile)
// .forEach(el -> files.add(el.toFile()));
// }
//
//
// List<String> javFiles = files.stream().filter(el -> el.getName().split("\\.").length >= 2 && el.getName().split("\\.")[el.getName().split("\\.").length - 1].contains("jav")).map(el -> el.getPath().replace(inputDir.getPath(), "").substring(1)).toList();
// //TODO: Link between Files
// generateClassFiles(new ByteArrayClassLoader(), Path.of(inputDir.toURI()), Path.of(outFile.toURI()), javFiles.toArray(new String[0]));
// System.setOut(System.out);
}
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,51 +0,0 @@
package languageServerInterfaceTest;
import de.dhbwstuttgart.core.ConsoleInterface;
import de.dhbwstuttgart.core.JavaTXCompiler;
import de.dhbwstuttgart.syntaxtree.factory.NameGenerator;
import de.dhbwstuttgart.syntaxtree.visual.ASTPrinter;
import org.junit.Ignore;
import org.junit.Test;
import de.dhbwstuttgart.languageServerInterface.LanguageServerInterface;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.List;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
public class LangaugeServerInterfaceTest {
@Test
@Ignore
public void consoleInterfaceTest() throws IOException, ClassNotFoundException, URISyntaxException {
LanguageServerInterface languageServerInterface = new LanguageServerInterface();
var resp = languageServerInterface.getResultSetAndAbstractSyntax("/home/ruben/code/JavaCompilerCore/src/test/java/languageServerInterfaceTest/test.jav");
System.out.println("\n-----------------------------------------\n");
System.out.println(ASTPrinter.print(resp.getAst()));
System.out.println("\n-----------------------------------------\n");
LanguageServerInterface languageServerInterface2 = new LanguageServerInterface();
var ast = languageServerInterface2.getAst("/home/ruben/code/JavaCompilerCore/src/test/java/languageServerInterfaceTest/test.jav", "N");
System.out.println("\n-----------------------------------------\n");
System.out.println(ASTPrinter.print(ast));
System.out.println("\n-----------------------------------------\n");
System.out.println("");
}
@Test
@Ignore
public void testBytecodeGen() throws IOException, ClassNotFoundException, URISyntaxException {
//TODO: Ordner und Datei löschen wenn sie bereits existieren
LanguageServerInterface languageServerInterface = new LanguageServerInterface();
languageServerInterface.generateBytecode(new URI("c%3A/Users/ruben/Neuer%20Ordner%20%282%29/LSP-Vortrag/images/"));
}
}

View File

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