Allow packages

This commit is contained in:
Daniel Holle 2023-10-18 16:54:41 +02:00
parent 0b815950e1
commit 628f1631e8
19 changed files with 221 additions and 98 deletions

View File

@ -1,21 +0,0 @@
public class Switch {
public static void main(String[] args) {
CharSequence s = "some string";
/*var res = switch (s) {
case "AaAaAa" -> 20;
case "AaAaBB" -> 30;
case String y -> 40;
case CharSequence cs -> 30;
};*/
var i = s instanceof String s2;
//System.out.println(s2);
if (!(s instanceof String s2)) {
System.out.println(s2);
} else {
System.out.println(s2);
}
}
}

View File

@ -54,8 +54,8 @@ http://maven.apache.org/maven-v4_0_0.xsd">
<version>3.11.0</version>
<configuration>
<compilerArgs>--enable-preview</compilerArgs>
<source>20</source>
<target>20</target>
<source>21</source>
<target>21</target>
</configuration>
</plugin>
<plugin>

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

View File

@ -0,0 +1,11 @@
package pkg.sub;
import pkg.sub2.Test2;
public class Test1 {
main() {
var t2 = new Test2();
t2.test();
}
}

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

View File

@ -0,0 +1,6 @@
package pkg.sub2;
public class Test2 {
test() {}
}

View File

@ -27,7 +27,7 @@ public class Codegen {
public Codegen(TargetStructure clazz, JavaTXCompiler compiler) {
this.clazz = clazz;
this.className = clazz.qualifiedName();
this.className = clazz.qualifiedName().getClassName();
this.cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS) {
@Override
protected ClassLoader getClassLoader() {
@ -743,7 +743,7 @@ public class Codegen {
desugared += "V";
var params = new ArrayList<TargetType>();
params.add(new TargetRefType(clazz.qualifiedName()));
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));
@ -1382,7 +1382,7 @@ public class Codegen {
if ((access & ACC_PRIVATE) == 0 && (access & ACC_PROTECTED) == 0) // TODO Implement access modifiers properly
access |= ACC_PUBLIC;
cw.visit(V1_8, access | ACC_SUPER, clazz.qualifiedName(), generateSignature(clazz, clazz.generics()), clazz.superType() != null ? clazz.superType().getInternalName() : "java/lang/Object", clazz.implementingInterfaces().stream().map(TargetType::toSignature).toArray(String[]::new));
cw.visit(V1_8, access | ACC_SUPER, clazz.qualifiedName().toString().replaceAll("\\.", "/"), 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)
cw.visitAttribute(new JavaTXSignatureAttribute(generateSignature(clazz, clazz.txGenerics())));

View File

@ -12,6 +12,7 @@ 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;
@ -30,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;
@ -72,6 +74,8 @@ public class JavaTXCompiler {
public volatile UnifyTaskModel usedTasks = new UnifyTaskModel();
private final DirectoryClassLoader classLoader;
private final List<File> classPath;
public DirectoryClassLoader getClassLoader() {
return classLoader;
}
@ -96,6 +100,8 @@ public class JavaTXCompiler {
}
classLoader = new DirectoryClassLoader(contextPath, ClassLoader.getSystemClassLoader());
environment = new CompilationEnvironment(sources);
classPath = contextPath;
for (File s : sources) {
sourceFiles.put(s, parse(s));
}
@ -109,11 +115,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);
}
@ -176,6 +180,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
@ -183,22 +200,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);
}
@ -253,7 +256,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();
@ -262,7 +265,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);
@ -384,7 +387,7 @@ 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) {
// Don't load classes that get recompiled
if (sf.getClasses().stream().anyMatch(nf -> nf.getClassName().equals(clazz.getClassName())))
@ -622,13 +625,52 @@ 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);
environment.addClassesToRegistry(classRegistry, tree, sourceFile, this);
SyntaxTreeGenerator generator = new SyntaxTreeGenerator(classRegistry, new GenericsRegistry(null));
SourceFile ret = generator.convert(tree, environment.packageCrawler, this);
return ret;
}
/**
* 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) {
if (classRegistry.contains(name.getClassName())) {
return true;
}
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(classRegistry, new GenericsRegistry(null));
sourceFiles.put(file, generator.convert(tree, environment.packageCrawler, this));
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 {
generateBytecode((File) null);
}

View File

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

View File

@ -12,6 +12,7 @@ import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import de.dhbwstuttgart.core.JavaTXCompiler;
import de.dhbwstuttgart.syntaxtree.*;
import de.dhbwstuttgart.syntaxtree.Record;
import org.antlr.v4.runtime.CommonToken;
@ -130,7 +131,7 @@ public class SyntaxTreeGenerator {
return ctx.getText();
}
public SourceFile convert(Java17Parser.SourceFileContext ctx, PackageCrawler packageCrawler, ClassLoader classLoader) throws ClassNotFoundException, NotImplementedException {
public SourceFile convert(Java17Parser.SourceFileContext ctx, PackageCrawler packageCrawler, JavaTXCompiler compiler) throws ClassNotFoundException, NotImplementedException {
SrcfileContext srcfile;
List<ClassOrInterface> classes = new ArrayList<>();
if (ctx instanceof Java17Parser.SrcfileContext) {
@ -140,7 +141,7 @@ public class SyntaxTreeGenerator {
}
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;

View File

@ -5,6 +5,8 @@ import java.util.List;
import java.util.Map;
import java.util.Objects;
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;
@ -25,19 +27,19 @@ 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<>();
for (Java17Parser.ClassOrInterfaceContext clsoifctx : ctx.classOrInterface()) {
if (clsoifctx instanceof NoclassorinterfaceContext) {
continue;
}
ret.putAll(getNames(clsoifctx, getPackageName(ctx), packages, classLoader));
ret.putAll(getNames(clsoifctx, getPackageName(ctx), packages, compiler));
}
ret.putAll(getImports(ctx, packages, classLoader));
ret.putAll(getImports(ctx, packages, compiler));
return ret;
}
public static Map<String, Integer> getNames(ClassOrInterfaceContext clsoifctx, String pkgName, PackageCrawler packages, ClassLoader classLoader) throws ClassNotFoundException {
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 = "";
@ -56,7 +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, classLoader));
ret.putAll(getNames(clsoif.classDeclaration().classBody().classBodyDeclaration(), pkgName, packages, compiler));
break;
case "EnumDeclarationContext":
if (!pkgName.isEmpty()) {
@ -71,7 +73,7 @@ public class GatherNames {
for (EnumConstantContext enumConstant : enumConstants.enumConstant()) {
ClassBodyContext enumConstClassBody = enumConstant.classBody();
if (!Objects.isNull(enumConstClassBody)) {
ret.putAll(getNames(enumConstClassBody.classBodyDeclaration(), pkgName, packages, classLoader));
ret.putAll(getNames(enumConstClassBody.classBodyDeclaration(), pkgName, packages, compiler));
}
}
}
@ -86,7 +88,7 @@ public class GatherNames {
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, classLoader));
ret.putAll(getNames(sub.classOrInterface(), pkgName, packages, compiler));
}
}
break;
@ -101,7 +103,7 @@ public class GatherNames {
for (AnnotationTypeElementDeclarationContext anTypeElem : clsoif.annotationTypeDeclaration().annotationTypeBody().annotationTypeElementDeclaration()) {
ClassOrInterfaceContext anClsoifctx = anTypeElem.annotationTypeElementRest().classOrInterface();
if (!Objects.isNull(anClsoifctx)) {
ret.putAll(getNames(anClsoifctx, pkgName, packages, classLoader));
ret.putAll(getNames(anClsoifctx, pkgName, packages, compiler));
}
}
break;
@ -113,7 +115,7 @@ 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, classLoader));
ret.putAll(getNames(clsoif.recordDeclaration().recordBody().classBodyDeclaration(), pkgName, packages, compiler));
break;
default:
throw new NotImplementedException();
@ -121,24 +123,31 @@ public class GatherNames {
return ret;
}
public static Map<String, Integer> getNames(List<ClassBodyDeclarationContext> clsBodyDecl, String pkgName, 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, classLoader));
ret.putAll(getNames(memberclsoifctx.classOrInterface(), pkgName, packages, compiler));
}
}
return ret;
}
public static Map<String, Integer> getImports(Java17Parser.SrcfileContext ctx, PackageCrawler packages, ClassLoader classLoader) throws ClassNotFoundException {
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());
ret.put(cl.getName(), cl.getTypeParameters().length);
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

View File

@ -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;

View File

@ -11,11 +11,21 @@ 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) {
for (JavaClassName name : existingClasses.keySet()) {
if (name.equals(new JavaClassName(className)))

View File

@ -145,8 +145,8 @@ public class ASTToTargetAST {
var methods = groupOverloads(input.getMethods()).stream().map(this::convert).flatMap(List::stream).toList();
if (input instanceof Record)
return new TargetRecord(input.getModifiers(), input.getClassName().toString(), javaGenerics, txGenerics, superInterfaces, constructors, fields, methods);
else return new TargetClass(input.getModifiers(), input.getClassName().toString(), convert(input.getSuperClass(), generics.javaGenerics), javaGenerics, txGenerics, superInterfaces, constructors, fields, methods);
return new TargetRecord(input.getModifiers(), input.getClassName(), javaGenerics, txGenerics, superInterfaces, constructors, fields, methods);
else return new TargetClass(input.getModifiers(), input.getClassName(), convert(input.getSuperClass(), generics.javaGenerics), javaGenerics, txGenerics, superInterfaces, constructors, fields, methods);
}
private List<MethodParameter> convert(ParameterList input, GenerateGenerics generics) {

View File

@ -1,22 +1,21 @@
package de.dhbwstuttgart.target.tree;
import de.dhbwstuttgart.target.tree.expression.TargetBlock;
import de.dhbwstuttgart.parser.scope.JavaClassName;
import de.dhbwstuttgart.target.tree.type.TargetRefType;
import de.dhbwstuttgart.target.tree.type.TargetType;
import java.lang.annotation.Target;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public record TargetClass(int modifiers, String qualifiedName, TargetType superType, Set<TargetGeneric> generics, Set<TargetGeneric> txGenerics, List<TargetType> implementingInterfaces,
public record TargetClass(int modifiers, JavaClassName qualifiedName, TargetType superType, Set<TargetGeneric> generics, Set<TargetGeneric> txGenerics, List<TargetType> implementingInterfaces,
List<TargetConstructor> constructors, List<TargetField> fields, List<TargetMethod> methods) implements TargetStructure {
public TargetClass(int modifiers, String qualifiedName) {
public TargetClass(int modifiers, JavaClassName qualifiedName) {
this(modifiers, qualifiedName, TargetType.Object, new HashSet<>(), new HashSet<>(), new ArrayList<>(), new ArrayList<>(), new ArrayList<>(), new ArrayList<>());
}
public TargetClass(int modifiers, String qualifiedName, List<TargetType> implementingInterfaces) {
public TargetClass(int modifiers, JavaClassName qualifiedName, List<TargetType> implementingInterfaces) {
this(modifiers, qualifiedName, TargetType.Object, new HashSet<>(), new HashSet<>(), implementingInterfaces, new ArrayList<>(), new ArrayList<>(), new ArrayList<>());
}

View File

@ -1,13 +1,13 @@
package de.dhbwstuttgart.target.tree;
import de.dhbwstuttgart.parser.scope.JavaClassName;
import de.dhbwstuttgart.target.tree.type.TargetRefType;
import de.dhbwstuttgart.target.tree.type.TargetType;
import java.util.Collections;
import java.util.List;
import java.util.Set;
public record TargetRecord(int modifiers, String qualifiedName, Set<TargetGeneric> generics, Set<TargetGeneric> txGenerics, List<TargetType> implementingInterfaces, List<TargetConstructor> constructors, List<TargetField> fields, List<TargetMethod> methods) implements TargetStructure {
public record TargetRecord(int modifiers, JavaClassName qualifiedName, Set<TargetGeneric> generics, Set<TargetGeneric> txGenerics, List<TargetType> implementingInterfaces, List<TargetConstructor> constructors, List<TargetField> fields, List<TargetMethod> methods) implements TargetStructure {
public static final TargetType RECORD = new TargetRefType("java.lang.Record");

View File

@ -1,5 +1,6 @@
package de.dhbwstuttgart.target.tree;
import de.dhbwstuttgart.parser.scope.JavaClassName;
import de.dhbwstuttgart.target.tree.expression.TargetBlock;
import de.dhbwstuttgart.target.tree.type.TargetType;
@ -8,7 +9,7 @@ import java.util.Set;
public interface TargetStructure {
int modifiers();
String qualifiedName();
JavaClassName qualifiedName();
TargetType superType();
Set<TargetGeneric> generics();
Set<TargetGeneric> txGenerics();
@ -18,7 +19,7 @@ public interface TargetStructure {
List<TargetMethod> methods();
default String getName() {
return qualifiedName().replaceAll("\\.", "/");
return qualifiedName().toString().replaceAll("\\.", "/");
}
// These methods are only meant to be used for test cases, a Class record should be immutable!

View File

@ -0,0 +1,36 @@
import de.dhbwstuttgart.core.JavaTXCompiler;
import org.junit.Test;
import java.io.File;
import java.util.List;
public class TestPackages {
private static final String bytecodeDirectory = System.getProperty("user.dir") + "/src/test/resources/testBytecode/generatedBC/";
@Test
public void testPackages() throws Exception {
var cmp = new JavaTXCompiler(
List.of(
new File("resources/packageTest/pkg/sub/Test1.jav") // This should pull in Test2
//new File("resources/packageTest/pkg/sub2/Test2.jav")
),
List.of(new File("resources/packageTest"))
);
cmp.generateBytecode(bytecodeDirectory);
}
@Test
public void testPackagesCircular() throws Exception {
var cmp = new JavaTXCompiler(
List.of(
new File("resources/packageTest/pkg/sub/Cycle1.jav")
//new File("resources/packageTest/pkg/sub2/Cycle2.jav")
),
List.of(new File("resources/packageTest"))
);
cmp.generateBytecode(bytecodeDirectory);
}
}

View File

@ -4,6 +4,7 @@ import de.dhbwstuttgart.core.JavaTXCompiler;
import de.dhbwstuttgart.bytecode.Codegen;
import de.dhbwstuttgart.environment.ByteArrayClassLoader;
import de.dhbwstuttgart.environment.IByteArrayClassLoader;
import de.dhbwstuttgart.parser.scope.JavaClassName;
import de.dhbwstuttgart.target.generate.ASTToTargetAST;
import de.dhbwstuttgart.target.tree.MethodParameter;
import de.dhbwstuttgart.target.tree.TargetClass;
@ -68,14 +69,14 @@ public class TestCodegen {
public static Class<?> generateClass(TargetStructure clazz, IByteArrayClassLoader classLoader) throws IOException, ClassNotFoundException {
Codegen codegen = new Codegen(clazz, new JavaTXCompiler(List.of()));
var code = codegen.generate();
writeClassFile(clazz.qualifiedName(), code);
writeClassFile(clazz.qualifiedName().getClassName(), code);
return classLoader.loadClass(code);
}
public static Class<?> generateClass(TargetStructure clazz, IByteArrayClassLoader classLoader, JavaTXCompiler compiler) throws IOException {
Codegen codegen = new Codegen(clazz, compiler);
var code = codegen.generate();
writeClassFile(clazz.qualifiedName(), code);
writeClassFile(clazz.qualifiedName().getClassName(), code);
return classLoader.loadClass(code);
}
@ -105,14 +106,14 @@ public class TestCodegen {
@Test
public void testEmptyClass() throws Exception {
var clazz = new TargetClass(Opcodes.ACC_PUBLIC, "Empty");
var clazz = new TargetClass(Opcodes.ACC_PUBLIC, new JavaClassName("Empty"));
clazz.addMethod(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "main", List.of(), null, new TargetBlock(List.of()));
generateClass(clazz, new ByteArrayClassLoader()).getDeclaredMethod("main").invoke(null);
}
@Test
public void testArithmetic() throws Exception {
var targetClass = new TargetClass(Opcodes.ACC_PUBLIC, "Arithmetic");
var targetClass = new TargetClass(Opcodes.ACC_PUBLIC, new JavaClassName("Arithmetic"));
targetClass.addMethod(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "add", List.of(new MethodParameter(TargetType.Integer, "a"), new MethodParameter(TargetType.Integer, "b")), TargetType.Integer, new TargetBlock(List.of(new TargetReturn(new TargetBinaryOp.Add(TargetType.Integer, new TargetLocalVar(TargetType.Integer, "a"), new TargetLocalVar(TargetType.Integer, "b"))))));
targetClass.addMethod(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "sub", List.of(new MethodParameter(TargetType.Integer, "a"), new MethodParameter(TargetType.Integer, "b")), TargetType.Integer, new TargetBlock(List.of(new TargetReturn(new TargetBinaryOp.Sub(TargetType.Integer, new TargetLocalVar(TargetType.Integer, "a"), new TargetLocalVar(TargetType.Integer, "b"))))));
@ -130,7 +131,7 @@ public class TestCodegen {
@Test
public void testUnary() throws Exception {
var targetClass = new TargetClass(Opcodes.ACC_PUBLIC, "Unary");
var targetClass = new TargetClass(Opcodes.ACC_PUBLIC, new JavaClassName("Unary"));
targetClass.addMethod(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "not", List.of(new MethodParameter(TargetType.Integer, "a")), TargetType.Integer, new TargetBlock(List.of(new TargetReturn(new TargetUnaryOp.Not(TargetType.Integer, new TargetLocalVar(TargetType.Integer, "a"))))));
targetClass.addMethod(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "neg", List.of(new MethodParameter(TargetType.Integer, "a")), TargetType.Integer, new TargetBlock(List.of(new TargetReturn(new TargetUnaryOp.Negate(TargetType.Integer, new TargetLocalVar(TargetType.Integer, "a"))))));
@ -145,7 +146,7 @@ public class TestCodegen {
@Test
public void testConditional() throws Exception {
var targetClass = new TargetClass(Opcodes.ACC_PUBLIC, "Conditional");
var targetClass = new TargetClass(Opcodes.ACC_PUBLIC, new JavaClassName("Conditional"));
targetClass.addMethod(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "and", List.of(new MethodParameter(TargetType.Boolean, "a"), new MethodParameter(TargetType.Boolean, "b")), TargetType.Boolean, new TargetBlock(List.of(new TargetReturn(new TargetBinaryOp.And(TargetType.Boolean, new TargetLocalVar(TargetType.Boolean, "a"), new TargetLocalVar(TargetType.Boolean, "b"))))));
targetClass.addMethod(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "or", List.of(new MethodParameter(TargetType.Boolean, "a"), new MethodParameter(TargetType.Boolean, "b")), TargetType.Boolean, new TargetBlock(List.of(new TargetReturn(new TargetBinaryOp.Or(TargetType.Boolean, new TargetLocalVar(TargetType.Boolean, "a"), new TargetLocalVar(TargetType.Boolean, "b"))))));
@ -162,7 +163,7 @@ public class TestCodegen {
// When adding two numbers and the return type is Long it needs to convert both values to Long
@Test
public void testArithmeticConvert() throws Exception {
var targetClass = new TargetClass(Opcodes.ACC_PUBLIC, "ArithmeticConvert");
var targetClass = new TargetClass(Opcodes.ACC_PUBLIC, new JavaClassName("ArithmeticConvert"));
targetClass.addMethod(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "add", List.of(), TargetType.Long, new TargetBlock(List.of(new TargetReturn(new TargetBinaryOp.Add(TargetType.Long, new TargetLiteral.CharLiteral((char) 10), new TargetLiteral.LongLiteral((long) 20))))));
var clazz = generateClass(targetClass, new ByteArrayClassLoader());
assertEquals(clazz.getDeclaredMethod("add").invoke(null), (long) 30);
@ -170,7 +171,7 @@ public class TestCodegen {
@Test
public void testMethodCall() throws Exception {
var targetClass = new TargetClass(Opcodes.ACC_PUBLIC, "HelloWorld");
var targetClass = new TargetClass(Opcodes.ACC_PUBLIC, new JavaClassName("HelloWorld"));
targetClass.addMethod(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "helloWorld", List.of(), null, new TargetBlock(List.of(new TargetMethodCall(null, new TargetFieldVar(new TargetRefType("java.io.PrintStream"), new TargetRefType("java.lang.System"), true, new TargetClassName(new TargetRefType("java.lang.System")), "out"), List.of(new TargetLiteral.StringLiteral("Hello World!")), new TargetRefType("java.io.PrintStream"), "println", false, false))));
var clazz = generateClass(targetClass, new ByteArrayClassLoader());
@ -179,7 +180,7 @@ public class TestCodegen {
@Test
public void testIfStatement() throws Exception {
var targetClass = new TargetClass(Opcodes.ACC_PUBLIC, "IfStmt");
var targetClass = new TargetClass(Opcodes.ACC_PUBLIC, new JavaClassName("IfStmt"));
targetClass.addMethod(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "ifStmt", List.of(new MethodParameter(TargetType.Integer, "val")), TargetType.Integer, new TargetBlock(List.of(new TargetIf(new TargetBinaryOp.Equal(TargetType.Integer, new TargetLocalVar(TargetType.Integer, "val"), new TargetLiteral.IntLiteral(10)), new TargetReturn(new TargetLiteral.IntLiteral(1)), new TargetIf(new TargetBinaryOp.Less(TargetType.Integer, new TargetLocalVar(TargetType.Integer, "val"), new TargetLiteral.IntLiteral(5)), new TargetReturn(new TargetLiteral.IntLiteral(2)), new TargetReturn(new TargetLiteral.IntLiteral(3)))))));
var clazz = generateClass(targetClass, new ByteArrayClassLoader());
var ifStmt = clazz.getDeclaredMethod("ifStmt", Integer.class);
@ -190,7 +191,7 @@ public class TestCodegen {
@Test
public void testFor() throws Exception {
var targetClass = new TargetClass(Opcodes.ACC_PUBLIC, "For");
var targetClass = new TargetClass(Opcodes.ACC_PUBLIC, new JavaClassName("For"));
targetClass.addMethod(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "forLoop", List.of(), TargetType.Integer, new TargetBlock(List.of(new TargetVarDecl(TargetType.Integer, "sum", new TargetLiteral.IntLiteral(0)), new TargetFor(new TargetVarDecl(TargetType.Integer, "i", new TargetLiteral.IntLiteral(0)), new TargetBinaryOp.Less(TargetType.Integer, new TargetLocalVar(TargetType.Integer, "i"), new TargetLiteral.IntLiteral(10)), new TargetAssign(TargetType.Integer, new TargetLocalVar(TargetType.Integer, "i"), new TargetBinaryOp.Add(TargetType.Integer, new TargetLocalVar(TargetType.Integer, "i"), new TargetLiteral.IntLiteral(1))), new TargetBlock(List.of(new TargetAssign(TargetType.Integer, new TargetLocalVar(TargetType.Integer, "sum"), new TargetBinaryOp.Add(TargetType.Integer, new TargetLocalVar(TargetType.Integer, "sum"), new TargetLocalVar(TargetType.Integer, "i")))))), new TargetReturn(new TargetLocalVar(TargetType.Integer, "sum")))));
var clazz = generateClass(targetClass, new ByteArrayClassLoader());
assertEquals(clazz.getDeclaredMethod("forLoop").invoke(null), 45);
@ -198,7 +199,7 @@ public class TestCodegen {
@Test
public void testWhile() throws Exception {
var targetClass = new TargetClass(Opcodes.ACC_PUBLIC, "While");
var targetClass = new TargetClass(Opcodes.ACC_PUBLIC, new JavaClassName("While"));
targetClass.addMethod(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "whileLoop", List.of(), TargetType.Integer, new TargetBlock(List.of(new TargetVarDecl(TargetType.Integer, "i", new TargetLiteral.IntLiteral(0)), new TargetWhile(new TargetBinaryOp.Less(TargetType.Integer, new TargetLocalVar(TargetType.Integer, "i"), new TargetLiteral.IntLiteral(10)), new TargetBlock(List.of(new TargetAssign(TargetType.Integer, new TargetLocalVar(TargetType.Integer, "i"), new TargetBinaryOp.Add(TargetType.Integer, new TargetLocalVar(TargetType.Integer, "i"), new TargetLiteral.IntLiteral(1)))))), new TargetReturn(new TargetLocalVar(TargetType.Integer, "i")))));
var clazz = generateClass(targetClass, new ByteArrayClassLoader());
assertEquals(clazz.getDeclaredMethod("whileLoop").invoke(null), 10);
@ -206,7 +207,7 @@ public class TestCodegen {
@Test
public void testClassicSwitch() throws Exception {
var targetClass = new TargetClass(Opcodes.ACC_PUBLIC , "SwitchClassic");
var targetClass = new TargetClass(Opcodes.ACC_PUBLIC , new JavaClassName("SwitchClassic"));
targetClass.addMethod(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "switchClassic", List.of(new MethodParameter(TargetType.Integer, "i")), TargetType.Integer, new TargetBlock(List.of(
new TargetVarDecl(TargetType.Integer, "res", null),
new TargetSwitch(new TargetLocalVar(TargetType.Integer, "i"), List.of(
@ -234,7 +235,7 @@ public class TestCodegen {
@Test
public void testTypeSwitch() throws Exception {
var targetClass = new TargetClass(Opcodes.ACC_PUBLIC, "SwitchEnhanced");
var targetClass = new TargetClass(Opcodes.ACC_PUBLIC, new JavaClassName("SwitchEnhanced"));
targetClass.addMethod(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "switchType", List.of(new MethodParameter(TargetType.Object, "obj")), TargetType.Integer, new TargetBlock(List.of(
new TargetReturn(new TargetSwitch(new TargetLocalVar(TargetType.Object, "obj"), List.of(
new TargetSwitch.Case(List.of(new TargetTypePattern(TargetType.String, "aString")), new TargetBlock(
@ -267,7 +268,7 @@ public class TestCodegen {
// var fun = classLoader.loadClass(Path.of(System.getProperty("user.dir"), "src/test/java/targetast/Fun1$$.class"));
var interfaceType = TargetFunNType.fromParams(List.of(TargetType.Integer));
var targetClass = new TargetClass(Opcodes.ACC_PUBLIC, "CGLambda");
var targetClass = new TargetClass(Opcodes.ACC_PUBLIC, new JavaClassName("CGLambda"));
targetClass.addConstructor(Opcodes.ACC_PUBLIC, List.of(), new TargetBlock(List.of(new TargetMethodCall(null, new TargetSuper(TargetType.Object), List.of(), TargetType.Object, "<init>", false, false))));
targetClass.addMethod(Opcodes.ACC_PUBLIC, "lambda", List.of(), TargetType.Integer, new TargetBlock(List.of(new TargetVarDecl(interfaceType, "by2", new TargetLambdaExpression(interfaceType, List.of(), List.of(new MethodParameter(TargetType.Integer, "num")), TargetType.Integer, new TargetBlock(List.of(new TargetReturn(new TargetBinaryOp.Mul(TargetType.Integer, new TargetLocalVar(TargetType.Integer, "num"), new TargetLiteral.IntLiteral(2))))))), new TargetReturn(new TargetCast(TargetType.Integer, new TargetMethodCall(TargetType.Object, TargetType.Object, List.of(TargetType.Object), new TargetLocalVar(interfaceType, "by2"), List.of(new TargetLiteral.IntLiteral(10)), interfaceType, "apply", false, true))))));
var clazz = generateClass(targetClass, classLoader);