Remove everything that doesn't touch constraints
Some checks failed
Build and Test with Maven / Build-and-test-with-Maven (push) Failing after 49s
Some checks failed
Build and Test with Maven / Build-and-test-with-Maven (push) Failing after 49s
This commit is contained in:
parent
edafbbc5a0
commit
494ce63838
@ -8,3 +8,4 @@ public class Main {
|
||||
ConsoleInterface.main(args);
|
||||
}
|
||||
}
|
||||
c
|
@ -1,7 +0,0 @@
|
||||
package de.dhbwstuttgart.bytecode;
|
||||
|
||||
public class CodeGenException extends RuntimeException {
|
||||
public CodeGenException(String cause) {
|
||||
super(cause);
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,196 +0,0 @@
|
||||
package de.dhbwstuttgart.bytecode;
|
||||
|
||||
import de.dhbwstuttgart.target.tree.TargetGeneric;
|
||||
import de.dhbwstuttgart.target.tree.type.*;
|
||||
import org.objectweb.asm.ClassWriter;
|
||||
import org.objectweb.asm.MethodVisitor;
|
||||
import org.objectweb.asm.Type;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static org.objectweb.asm.Opcodes.*;
|
||||
|
||||
/**
|
||||
* //ToDo beschreiben
|
||||
*
|
||||
* @since Studienarbeit Type Erasure
|
||||
* @author etiennezink
|
||||
*/
|
||||
public class FunNGenerator {
|
||||
|
||||
private static final String argumentGenericBase = "T";
|
||||
private static final String returnGeneric = "R";
|
||||
private static final String methodName = "apply";
|
||||
private static final int bytecodeVersion = V1_8;
|
||||
|
||||
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<>();
|
||||
final String descriptor;
|
||||
public final List<TargetType> inParams;
|
||||
|
||||
public GenericParameters(List<TargetType> params, int numReturns) {
|
||||
this.inParams = params;
|
||||
var type = new TargetRefType(FunNGenerator.getSuperClassName(params.size() - 1, numReturns), params);
|
||||
descriptor = applyDescriptor(type, this);
|
||||
}
|
||||
|
||||
public TargetType getReturnType() {
|
||||
return FunNGenerator.getReturnType(inParams);
|
||||
}
|
||||
|
||||
public List<TargetType> getArguments() {
|
||||
return FunNGenerator.getArguments(inParams);
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
res += "<";
|
||||
for (var param : a.params()) {
|
||||
if (param instanceof TargetGenericType gp) {
|
||||
gep.parameters.add(param);
|
||||
res += "TT" + gep.start + ";";
|
||||
gep.start += 1;
|
||||
} else {
|
||||
res += applyDescriptor(param, gep);
|
||||
}
|
||||
}
|
||||
res += ">";
|
||||
}
|
||||
} else {
|
||||
gep.parameters.add(null);
|
||||
return type.toDescriptor();
|
||||
}
|
||||
res += ";";
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
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)); }
|
||||
|
||||
public static String encodeType(TargetType type) {
|
||||
if (type == null) return VOID;
|
||||
return applyNameDescriptor(type).replace("/", "$").replace(";", "$_$");
|
||||
}
|
||||
|
||||
public static byte[] generateSuperBytecode(int numberArguments, int numReturnTypes) {
|
||||
StringBuilder superFunNClassSignature = new StringBuilder("<");
|
||||
StringBuilder superFunNMethodSignature = new StringBuilder("(");
|
||||
StringBuilder superFunNMethodDescriptor = new StringBuilder("(");
|
||||
|
||||
for (int currentParameter = 1; currentParameter <= numberArguments; currentParameter++){
|
||||
superFunNClassSignature.append(String.format("%s%d:%s", argumentGenericBase, currentParameter, objectSignature));
|
||||
superFunNMethodSignature.append(String.format("T%s;", argumentGenericBase + currentParameter));
|
||||
superFunNMethodDescriptor.append(objectSignature);
|
||||
}
|
||||
superFunNClassSignature.append(String.format("%s:%s>%s", returnGeneric, objectSignature, objectSignature));
|
||||
if (numReturnTypes > 0) {
|
||||
superFunNMethodSignature.append(String.format(")T%s;", returnGeneric));
|
||||
superFunNMethodDescriptor.append(String.format(")%s", objectSignature));
|
||||
} else {
|
||||
superFunNMethodSignature.append(")V");
|
||||
superFunNMethodDescriptor.append(")V");
|
||||
}
|
||||
|
||||
System.out.println(superFunNMethodSignature);
|
||||
|
||||
ClassWriter classWriter = new ClassWriter(0);
|
||||
MethodVisitor methodVisitor;
|
||||
classWriter.visit(bytecodeVersion, ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE, getSuperClassName(numberArguments, numReturnTypes), superFunNClassSignature.toString(), objectSuperType, null);
|
||||
methodVisitor = classWriter.visitMethod(ACC_PUBLIC | ACC_ABSTRACT, methodName, superFunNMethodDescriptor.toString(), superFunNMethodSignature.toString(), null);
|
||||
methodVisitor.visitEnd();
|
||||
classWriter.visitEnd();
|
||||
return classWriter.toByteArray();
|
||||
}
|
||||
|
||||
public static String getSuperClassName(int numberArguments, int returnArguments) {
|
||||
return returnArguments > 0 ? String.format("Fun%d$$", numberArguments) : String.format("FunVoid%d$$", numberArguments);
|
||||
}
|
||||
|
||||
public static byte[] generateSpecializedBytecode(GenericParameters gep, List<String> superInterfaces) {
|
||||
var argumentTypes = gep.getArguments();
|
||||
var returnType = gep.getReturnType();
|
||||
|
||||
StringBuilder funNClassSignature = new StringBuilder(objectSignature + gep.descriptor);
|
||||
boolean containsGeneric = false;
|
||||
|
||||
String genericSignature = "<";
|
||||
for (var i = 0; i < gep.start; i++) {
|
||||
genericSignature += String.format("T%d:%s", i, objectSignature);
|
||||
containsGeneric = true;
|
||||
}
|
||||
|
||||
genericSignature += ">";
|
||||
if (containsGeneric) funNClassSignature.insert(0, genericSignature);
|
||||
|
||||
for (var superInterface : superInterfaces) {
|
||||
funNClassSignature.append('L');
|
||||
funNClassSignature.append(superInterface);
|
||||
funNClassSignature.append(';');
|
||||
}
|
||||
|
||||
var interfaces = new ArrayList<>(superInterfaces);
|
||||
interfaces.add(getSuperClassName(argumentTypes.size(), returnType != null ? 1 : 0));
|
||||
|
||||
ClassWriter classWriter = new ClassWriter(0);
|
||||
classWriter.visit(bytecodeVersion, ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE, getSpecializedClassName(argumentTypes, returnType), funNClassSignature.toString(), objectSuperType, interfaces.toArray(String[]::new));
|
||||
classWriter.visitEnd();
|
||||
return classWriter.toByteArray();
|
||||
}
|
||||
|
||||
private static void collectGenericTypeArguments(Map<TargetGenericType, Integer> generics, TargetType typeArgument) {
|
||||
if (typeArgument instanceof TargetSpecializedType specializedType) {
|
||||
for (var arg : specializedType.params())
|
||||
collectGenericTypeArguments(generics, arg);
|
||||
} else if (typeArgument instanceof TargetGenericType genericType) {
|
||||
if (generics.containsKey(genericType))
|
||||
generics.put(genericType, generics.get(genericType) + 1);
|
||||
else generics.put(genericType, 0);
|
||||
}
|
||||
}
|
||||
|
||||
public static String getSpecializedClassName(GenericParameters gep) {
|
||||
return getSpecializedClassName(getArguments(gep.inParams), getReturnType(gep.inParams));
|
||||
}
|
||||
|
||||
public static String getSpecializedClassName(List<TargetType> argumentTypes, TargetType returnType) {
|
||||
var arguments = argumentTypes
|
||||
.stream()
|
||||
.map(FunNGenerator::encodeType)
|
||||
.collect(Collectors.joining());
|
||||
|
||||
if (returnType != null)
|
||||
return String.format("Fun%d$$%s%s",
|
||||
argumentTypes.size(),
|
||||
arguments,
|
||||
encodeType(returnType));
|
||||
else return String.format("FunVoidImpl%d$$%s",
|
||||
argumentTypes.size(),
|
||||
arguments);
|
||||
}
|
||||
|
||||
public static List<TargetType> getArguments(List<TargetType> list) {
|
||||
return list
|
||||
.stream()
|
||||
.limit(Math.max(0, list.size() - 1))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public static TargetType getReturnType(List<TargetType> list) {
|
||||
if(list.isEmpty())
|
||||
throw new IndexOutOfBoundsException();
|
||||
return list.getLast();
|
||||
}
|
||||
}
|
@ -1,30 +0,0 @@
|
||||
package de.dhbwstuttgart.bytecode;
|
||||
|
||||
import org.objectweb.asm.*;
|
||||
|
||||
public class JavaTXSignatureAttribute extends Attribute {
|
||||
public String signature;
|
||||
|
||||
public JavaTXSignatureAttribute() {
|
||||
super("JavaTXSignature");
|
||||
}
|
||||
protected JavaTXSignatureAttribute(String signature) {
|
||||
this();
|
||||
this.signature = signature;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Attribute read(ClassReader classReader, int offset, int length, char[] charBuffer, int codeAttributeOffset, Label[] labels) {
|
||||
var data = new byte[length];
|
||||
System.arraycopy(classReader.b, offset, data, 0, length);
|
||||
var constantPoolOffset = data[0] << 8 | data[1];
|
||||
return new JavaTXSignatureAttribute((String) classReader.readConst(constantPoolOffset, charBuffer));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ByteVector write(ClassWriter classWriter, byte[] code, int codeLength, int maxStack, int maxLocals) {
|
||||
var data = new ByteVector();
|
||||
data.putShort(classWriter.newConst(this.signature));
|
||||
return data;
|
||||
}
|
||||
}
|
@ -39,7 +39,7 @@ public class ConsoleInterface {
|
||||
}
|
||||
JavaTXCompiler compiler = new JavaTXCompiler(input, classpath, outputPath != null ? new File(outputPath) : null);
|
||||
//compiler.typeInference();
|
||||
compiler.generateBytecode();
|
||||
compiler.run();
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,7 +1,6 @@
|
||||
//PL 2018-12-19: typeInferenceOld nach typeInference uebertragen
|
||||
package de.dhbwstuttgart.core;
|
||||
|
||||
import de.dhbwstuttgart.bytecode.Codegen;
|
||||
import de.dhbwstuttgart.environment.CompilationEnvironment;
|
||||
import de.dhbwstuttgart.environment.DirectoryClassLoader;
|
||||
import de.dhbwstuttgart.exceptions.DebugException;
|
||||
@ -19,7 +18,6 @@ import de.dhbwstuttgart.syntaxtree.ParameterList;
|
||||
import de.dhbwstuttgart.syntaxtree.SourceFile;
|
||||
import de.dhbwstuttgart.syntaxtree.GenericDeclarationList;
|
||||
import de.dhbwstuttgart.syntaxtree.factory.ASTFactory;
|
||||
import de.dhbwstuttgart.syntaxtree.factory.UnifyTypeFactory;
|
||||
import de.dhbwstuttgart.syntaxtree.type.ExtendsWildcardType;
|
||||
import de.dhbwstuttgart.syntaxtree.type.GenericRefType;
|
||||
import de.dhbwstuttgart.syntaxtree.type.RefType;
|
||||
@ -27,38 +25,15 @@ import de.dhbwstuttgart.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric;
|
||||
import de.dhbwstuttgart.syntaxtree.type.SuperWildcardType;
|
||||
import de.dhbwstuttgart.syntaxtree.type.TypePlaceholder;
|
||||
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.typeinference.constraints.Constraint;
|
||||
import de.dhbwstuttgart.typeinference.constraints.ConstraintSet;
|
||||
import de.dhbwstuttgart.typeinference.constraints.Pair;
|
||||
import de.dhbwstuttgart.typeinference.result.ResultSet;
|
||||
import de.dhbwstuttgart.typeinference.typeAlgo.TYPE;
|
||||
import de.dhbwstuttgart.typeinference.unify.RuleSet;
|
||||
import de.dhbwstuttgart.typeinference.unify.TypeUnify;
|
||||
import de.dhbwstuttgart.typeinference.unify.distributeVariance;
|
||||
import de.dhbwstuttgart.typeinference.unify.interfaces.IFiniteClosure;
|
||||
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.typeinference.unify.TypeUnifyTask;
|
||||
import de.dhbwstuttgart.typeinference.unify.UnifyResultListener;
|
||||
import de.dhbwstuttgart.typeinference.unify.UnifyResultListenerImpl;
|
||||
import de.dhbwstuttgart.typeinference.unify.UnifyResultModel;
|
||||
import de.dhbwstuttgart.typeinference.unify.UnifyTaskModel;
|
||||
|
||||
import java.io.*;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.commons.io.output.NullOutputStream;
|
||||
|
||||
public class JavaTXCompiler {
|
||||
|
||||
// public static JavaTXCompiler INSTANCE;
|
||||
@ -67,12 +42,15 @@ public class JavaTXCompiler {
|
||||
public final Map<File, SourceFile> sourceFiles = new HashMap<>();
|
||||
|
||||
Boolean log = true; //gibt an ob ein Log-File nach System.getProperty("user.dir")+""/logFiles/"" geschrieben werden soll?
|
||||
public volatile UnifyTaskModel usedTasks = new UnifyTaskModel();
|
||||
public final DirectoryClassLoader classLoader;
|
||||
|
||||
public final List<File> classPath;
|
||||
private final File outputPath;
|
||||
|
||||
public final JavaClassRegistry classRegistry = new JavaClassRegistry();
|
||||
public record ClassEntry(File classFile, ClassOrInterface cif) {}
|
||||
public final Map<JavaClassName, ClassEntry> loadedClasses = new HashMap<>();
|
||||
|
||||
public DirectoryClassLoader getClassLoader() {
|
||||
return classLoader;
|
||||
}
|
||||
@ -108,6 +86,30 @@ public class JavaTXCompiler {
|
||||
// INSTANCE = this;
|
||||
}
|
||||
|
||||
private SourceFile parse(File sourceFile) throws IOException, java.lang.ClassNotFoundException {
|
||||
if (sourceFiles.containsKey(sourceFile)) return sourceFiles.get(sourceFile);
|
||||
SourceFileContext tree = JavaTXParser.parse(sourceFile);
|
||||
environment.addClassesToRegistry(classRegistry, tree, sourceFile, this);
|
||||
SyntaxTreeGenerator generator = new SyntaxTreeGenerator(this, classRegistry, new GenericsRegistry(null), sourceFile.getName());
|
||||
var classes = new ArrayList<ClassOrInterface>();
|
||||
var sf = new SourceFile("", classes, generator.imports);
|
||||
addSourceFile(sourceFile, sf);
|
||||
generator.convert(classes, tree, environment.packageCrawler);
|
||||
sf.setPackageName(generator.pkgName);
|
||||
sf.imports.addAll(generator.imports);
|
||||
return sf;
|
||||
}
|
||||
|
||||
public void run() throws IOException, ClassNotFoundException {
|
||||
for (var file : sourceFiles.keySet()) {
|
||||
var sf = sourceFiles.get(file);
|
||||
if (sf.isGenerated()) continue;
|
||||
sf.setGenerated();
|
||||
parse(file);
|
||||
getConstraints(file);
|
||||
}
|
||||
}
|
||||
|
||||
private void addSourceFile(File file, SourceFile sf) {
|
||||
sourceFiles.put(file, sf);
|
||||
}
|
||||
@ -239,446 +241,6 @@ public class JavaTXCompiler {
|
||||
return allClasses;
|
||||
}
|
||||
|
||||
/*
|
||||
* public List<ResultSet> typeInferenceOld() throws ClassNotFoundException { List<ClassOrInterface> allClasses = new ArrayList<>();//environment.getAllAvailableClasses(); //Alle Importierten Klassen in allen geparsten Sourcefiles kommen ins FC for(SourceFile sf : this.sourceFiles.values()) { allClasses.addAll(getAvailableClasses(sf)); allClasses.addAll(sf.getClasses()); }
|
||||
*
|
||||
* final ConstraintSet<Pair> cons = getConstraints();
|
||||
*
|
||||
* FiniteClosure finiteClosure = UnifyTypeFactory.generateFC(allClasses); System.out.println(finiteClosure); ConstraintSet<UnifyPair> unifyCons = UnifyTypeFactory.convert(cons);
|
||||
*
|
||||
* TypeUnify unify = new TypeUnify(); Set<Set<UnifyPair>> results = new HashSet<>(); try { File logPath = new File(System.getProperty("user.dir")+"/target/logFiles/"); logPath.mkdirs(); FileWriter logFile = new FileWriter(new File(logPath, "log")); logFile.write("FC:\\" + finiteClosure.toString()+"\n"); for(SourceFile sf : this.sourceFiles.values()) { logFile.write(ASTTypePrinter.print(sf)); } logFile.flush(); Set<List<Constraint<UnifyPair>>> cardProd = unifyCons.cartesianProduct(); for
|
||||
* (List<Constraint<UnifyPair>> xCons : cardProd ){ Set<UnifyPair> xConsSet = new HashSet<>(); for (Constraint<UnifyPair> constraint : xCons) { xConsSet.addAll(constraint); } //.collect(Collectors.toCollection(ArrayList::new)))) System.out.println(xConsSet); Set<String> methodParaTypeVarNames = allClasses.stream().map(x -> x.getMethods().stream().map(y -> y.getParameterList().getFormalparalist() .stream().filter(z -> z.getType() instanceof TypePlaceholder) .map(z ->
|
||||
* ((TypePlaceholder)z.getType()).getName()).collect(Collectors.toCollection( HashSet::new))) .reduce(new HashSet<String>(), (a,b) -> { a.addAll(b); return a;}, (a,b) -> { a.addAll(b); return a;} ) ) .reduce(new HashSet<String>(), (a,b) -> { a.addAll(b); return a;} );
|
||||
*
|
||||
* Set<String> constructorParaTypeVarNames = allClasses.stream().map(x -> x.getConstructors().stream().map(y -> y.getParameterList().getFormalparalist() .stream().filter(z -> z.getType() instanceof TypePlaceholder) .map(z -> ((TypePlaceholder)z.getType()).getName()).collect(Collectors.toCollection( HashSet::new))) .reduce(new HashSet<String>(), (a,b) -> { a.addAll(b); return a;}, (a,b) -> { a.addAll(b); return a;} ) ) .reduce(new HashSet<String>(), (a,b) -> { a.addAll(b); return a;} );
|
||||
*
|
||||
* Set<String> paraTypeVarNames = methodParaTypeVarNames; paraTypeVarNames.addAll(constructorParaTypeVarNames);
|
||||
*
|
||||
* Set<String> returnTypeVarNames = allClasses.stream().map(x -> x.getMethods().stream().filter(y -> y.getReturnType() instanceof TypePlaceholder) .map(z -> ((TypePlaceholder)z.getReturnType()).getName()).collect(Collectors. toCollection(HashSet::new))).reduce((a,b) -> { a.addAll(b); return a;} ).get();
|
||||
*
|
||||
* Set<String> fieldTypeVarNames = allClasses.stream().map(x -> x.getFieldDecl().stream().filter(y -> y.getReturnType() instanceof TypePlaceholder) .map(z -> ((TypePlaceholder)z.getReturnType()).getName()).collect(Collectors. toCollection(HashSet::new))).reduce((a,b) -> { a.addAll(b); return a;} ).get();
|
||||
*
|
||||
* returnTypeVarNames.addAll(fieldTypeVarNames);
|
||||
*
|
||||
* xConsSet = xConsSet.stream().map(x -> { //Hier muss ueberlegt werden, ob //1. alle Argument- und Retuntyp-Variablen in allen UnifyPairs // mit disableWildcardtable() werden. //2. alle Typvariablen mit Argument- oder Retuntyp-Variablen //in Beziehung auch auf disableWildcardtable() gesetzt werden muessen //PL 2018-04-23 if ((x.getLhsType() instanceof PlaceholderType)) { if (paraTypeVarNames.contains(x.getLhsType().getName())) { ((PlaceholderType)x.getLhsType()).setVariance((byte)1);
|
||||
* ((PlaceholderType)x.getLhsType()).disableWildcardtable(); } if (returnTypeVarNames.contains(x.getLhsType().getName())) { ((PlaceholderType)x.getLhsType()).setVariance((byte)-1); ((PlaceholderType)x.getLhsType()).disableWildcardtable(); } } if ((x.getRhsType() instanceof PlaceholderType)) { if (paraTypeVarNames.contains(x.getRhsType().getName())) { ((PlaceholderType)x.getRhsType()).setVariance((byte)1); ((PlaceholderType)x.getRhsType()).disableWildcardtable(); } if
|
||||
* (returnTypeVarNames.contains(x.getRhsType().getName())) { ((PlaceholderType)x.getRhsType()).setVariance((byte)-1); ((PlaceholderType)x.getRhsType()).disableWildcardtable(); } } return x;//HIER DIE JEWEILS RECHT BZW. LINKE SEITE AUF GLEICHE VARIANZ SETZEN WIE DIE JEWEILS ANDERE SEITE }).map( y -> { if ((y.getLhsType() instanceof PlaceholderType) && (y.getRhsType() instanceof PlaceholderType)) { if (((PlaceholderType)y.getLhsType()).getVariance() != 0 &&
|
||||
* ((PlaceholderType)y.getRhsType()).getVariance() == 0) { ((PlaceholderType)y.getRhsType()).setVariance(((PlaceholderType)y.getLhsType( )).getVariance()); } if (((PlaceholderType)y.getLhsType()).getVariance() == 0 && ((PlaceholderType)y.getRhsType()).getVariance() != 0) { ((PlaceholderType)y.getLhsType()).setVariance(((PlaceholderType)y.getRhsType( )).getVariance()); } } return y; } ) .collect(Collectors.toCollection(HashSet::new)); varianceInheritance(xConsSet); Set<Set<UnifyPair>> result =
|
||||
* unify.unifySequential(xConsSet, finiteClosure, logFile, log); //Set<Set<UnifyPair>> result = unify.unify(xConsSet, finiteClosure); System.out.println("RESULT: " + result); logFile.write("RES: " + result.toString()+"\n"); logFile.flush(); results.addAll(result); }
|
||||
*
|
||||
* results = results.stream().map(x -> { Optional<Set<UnifyPair>> res = new RuleSet().subst(x.stream().map(y -> { if (y.getPairOp() == PairOperator.SMALLERDOTWC) y.setPairOp(PairOperator.EQUALSDOT); return y; //alle Paare a <.? b erden durch a =. b ersetzt }).collect(Collectors.toCollection(HashSet::new))); if (res.isPresent()) {//wenn subst ein Erg liefert wurde was veraendert return new TypeUnifyTask().applyTypeUnificationRules(res.get(), finiteClosure); } else return x; //wenn nichts
|
||||
* veraendert wurde wird x zurueckgegeben }).collect(Collectors.toCollection(HashSet::new)); System.out.println("RESULT Final: " + results); logFile.write("RES_FINAL: " + results.toString()+"\n"); logFile.flush(); logFile.write("PLACEHOLDERS: " + PlaceholderType.EXISTING_PLACEHOLDERS); logFile.flush(); } catch (IOException e) { e.printStackTrace(); } return results.stream().map((unifyPairs -> new ResultSet(UnifyTypeFactory.convert(unifyPairs,
|
||||
* generateTPHMap(cons))))).collect(Collectors.toList()); }
|
||||
*/
|
||||
/**
|
||||
* Vererbt alle Variancen bei Paaren (a <. theta) oder (Theta <. a) wenn a eine Variance !=0 hat auf alle Typvariablen in Theta.
|
||||
*
|
||||
*
|
||||
*/
|
||||
/*
|
||||
* private void varianceInheritance(Set<UnifyPair> eq) { Set<PlaceholderType> usedTPH = new HashSet<>(); Set<PlaceholderType> phSet = eq.stream().map(x -> { Set<PlaceholderType> pair = new HashSet<>(); if (x.getLhsType() instanceof PlaceholderType) pair.add((PlaceholderType)x.getLhsType()); if (x.getRhsType() instanceof PlaceholderType) pair.add((PlaceholderType)x.getRhsType()); return pair; }).reduce(new HashSet<>(), (a,b) -> { a.addAll(b); return a;} , (c,d) -> { c.addAll(d); return c;});
|
||||
*
|
||||
* ArrayList<PlaceholderType> phSetVariance = new ArrayList<>(phSet); phSetVariance.removeIf(x -> (x.getVariance() == 0)); while(!phSetVariance.isEmpty()) { PlaceholderType a = phSetVariance.remove(0); usedTPH.add(a); //HashMap<PlaceholderType,Integer> ht = new HashMap<>(); //ht.put(a, a.getVariance()); Set<UnifyPair> eq1 = new HashSet<>(eq); eq1.removeIf(x -> !(x.getLhsType() instanceof PlaceholderType && ((PlaceholderType)x.getLhsType()).equals(a))); eq1.stream().forEach(x -> {
|
||||
* x.getRhsType().accept(new distributeVariance(), a.getVariance());}); eq1 = new HashSet<>(eq); eq1.removeIf(x -> !(x.getRhsType() instanceof PlaceholderType && ((PlaceholderType)x.getRhsType()).equals(a))); eq1.stream().forEach(x -> { x.getLhsType().accept(new distributeVariance(), a.getVariance());}); phSetVariance = new ArrayList<>(phSet); phSetVariance.removeIf(x -> (x.getVariance() == 0 || usedTPH.contains(x))); } }
|
||||
*/
|
||||
|
||||
public UnifyResultModel typeInferenceAsync(UnifyResultListener resultListener, Writer logFile) throws ClassNotFoundException, IOException {
|
||||
List<ClassOrInterface> allClasses = new ArrayList<>();// environment.getAllAvailableClasses();
|
||||
// Alle Importierten Klassen in allen geparsten Sourcefiles kommen ins FC
|
||||
for (Entry<File, SourceFile> source : this.sourceFiles.entrySet()) {
|
||||
SourceFile sf = source.getValue();
|
||||
allClasses.addAll(getAvailableClasses(sf));
|
||||
allClasses.addAll(sf.getClasses());
|
||||
allClasses.addAll(CompilationEnvironment.loadDefaultPackageClasses(sf.getPkgName(), source.getKey(), this).stream().map(ASTFactory::createClass).collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
final ConstraintSet<Pair> cons = new ConstraintSet<>();
|
||||
for (var f : this.sourceFiles.keySet()) {
|
||||
cons.addAll(getConstraints(f));
|
||||
}
|
||||
|
||||
Set<Set<UnifyPair>> results = new HashSet<>();
|
||||
UnifyResultModel urm = null;
|
||||
// urm.addUnifyResultListener(resultListener);
|
||||
try {
|
||||
logFile = logFile == null ? new FileWriter(new File("log_" + sourceFiles.keySet().iterator().next().getName())) : logFile;
|
||||
IFiniteClosure finiteClosure = UnifyTypeFactory.generateFC(allClasses, logFile, getClassLoader(), this);
|
||||
System.out.println(finiteClosure);
|
||||
urm = new UnifyResultModel(cons, finiteClosure);
|
||||
urm.addUnifyResultListener(resultListener);
|
||||
ConstraintSet<UnifyPair> unifyCons = UnifyTypeFactory.convert(this, cons);
|
||||
|
||||
Function<UnifyPair, UnifyPair> distributeInnerVars = x -> {
|
||||
UnifyType lhs, rhs;
|
||||
if (((lhs = x.getLhsType()) instanceof PlaceholderType) && ((rhs = x.getRhsType()) instanceof PlaceholderType) && (((PlaceholderType) lhs).isInnerType() || ((PlaceholderType) rhs).isInnerType())) {
|
||||
((PlaceholderType) lhs).setInnerType(true);
|
||||
((PlaceholderType) rhs).setInnerType(true);
|
||||
}
|
||||
return x;
|
||||
|
||||
};
|
||||
logFile.write(unifyCons.toString());
|
||||
unifyCons = unifyCons.map(distributeInnerVars);
|
||||
logFile.write(unifyCons.toString());
|
||||
TypeUnify unify = new TypeUnify();
|
||||
// Set<Set<UnifyPair>> results = new HashSet<>(); Nach vorne gezogen
|
||||
logFile.write("FC:\\" + finiteClosure.toString() + "\n");
|
||||
for (SourceFile f : this.sourceFiles.values()) {
|
||||
logFile.write(ASTTypePrinter.print(f));
|
||||
}
|
||||
logFile.flush();
|
||||
|
||||
Set<String> methodParaTypeVarNames = allClasses.stream().map(x -> x.getMethods().stream().map(y -> y.getParameterList().getFormalparalist().stream().filter(z -> z.getType() instanceof TypePlaceholder).map(z -> ((TypePlaceholder) z.getType()).getName()).collect(Collectors.toCollection(HashSet::new))).reduce(new HashSet<String>(), (a, b) -> {
|
||||
a.addAll(b);
|
||||
return a;
|
||||
}, (a, b) -> {
|
||||
a.addAll(b);
|
||||
return a;
|
||||
})).reduce(new HashSet<String>(), (a, b) -> {
|
||||
a.addAll(b);
|
||||
return a;
|
||||
});
|
||||
|
||||
Set<String> constructorParaTypeVarNames = allClasses.stream().map(x -> x.getConstructors().stream().map(y -> y.getParameterList().getFormalparalist().stream().filter(z -> z.getType() instanceof TypePlaceholder).map(z -> ((TypePlaceholder) z.getType()).getName()).collect(Collectors.toCollection(HashSet::new))).reduce(new HashSet<String>(), (a, b) -> {
|
||||
a.addAll(b);
|
||||
return a;
|
||||
}, (a, b) -> {
|
||||
a.addAll(b);
|
||||
return a;
|
||||
})).reduce(new HashSet<String>(), (a, b) -> {
|
||||
a.addAll(b);
|
||||
return a;
|
||||
});
|
||||
|
||||
Set<String> paraTypeVarNames = methodParaTypeVarNames;
|
||||
paraTypeVarNames.addAll(constructorParaTypeVarNames);
|
||||
|
||||
Set<String> returnTypeVarNames = allClasses.stream().map(x -> x.getMethods().stream().filter(y -> y.getReturnType() instanceof TypePlaceholder).map(z -> ((TypePlaceholder) z.getReturnType()).getName()).collect(Collectors.toCollection(HashSet::new))).reduce((a, b) -> {
|
||||
a.addAll(b);
|
||||
return a;
|
||||
}).get();
|
||||
|
||||
Set<String> fieldTypeVarNames = allClasses.stream().map(x -> x.getFieldDecl().stream().filter(y -> y.getReturnType() instanceof TypePlaceholder).map(z -> ((TypePlaceholder) z.getReturnType()).getName()).collect(Collectors.toCollection(HashSet::new))).reduce((a, b) -> {
|
||||
a.addAll(b);
|
||||
return a;
|
||||
}).get();
|
||||
|
||||
returnTypeVarNames.addAll(fieldTypeVarNames);
|
||||
|
||||
unifyCons = unifyCons.map(x -> {
|
||||
// Hier muss ueberlegt werden, ob
|
||||
// 1. alle Argument- und Retuntyp-Variablen in allen UnifyPairs
|
||||
// mit disableWildcardtable() werden.
|
||||
// 2. alle Typvariablen mit Argument- oder Retuntyp-Variablen
|
||||
// in Beziehung auch auf disableWildcardtable() gesetzt werden muessen
|
||||
// PL 2018-04-23
|
||||
if ((x.getLhsType() instanceof PlaceholderType)) {
|
||||
if (paraTypeVarNames.contains(x.getLhsType().getName())) {
|
||||
((PlaceholderType) x.getLhsType()).setVariance((byte) 1);
|
||||
((PlaceholderType) x.getLhsType()).disableWildcardtable();
|
||||
}
|
||||
if (returnTypeVarNames.contains(x.getLhsType().getName())) {
|
||||
((PlaceholderType) x.getLhsType()).setVariance((byte) -1);
|
||||
((PlaceholderType) x.getLhsType()).disableWildcardtable();
|
||||
}
|
||||
}
|
||||
if ((x.getRhsType() instanceof PlaceholderType)) {
|
||||
if (paraTypeVarNames.contains(x.getRhsType().getName())) {
|
||||
((PlaceholderType) x.getRhsType()).setVariance((byte) 1);
|
||||
((PlaceholderType) x.getRhsType()).disableWildcardtable();
|
||||
}
|
||||
if (returnTypeVarNames.contains(x.getRhsType().getName())) {
|
||||
((PlaceholderType) x.getRhsType()).setVariance((byte) -1);
|
||||
((PlaceholderType) x.getRhsType()).disableWildcardtable();
|
||||
}
|
||||
}
|
||||
return x;// HIER DIE JEWEILS RECHT BZW. LINKE SEITE AUF GLEICHE VARIANZ SETZEN WIE DIE
|
||||
// JEWEILS ANDERE SEITE
|
||||
});
|
||||
Set<PlaceholderType> varianceTPHold;
|
||||
Set<PlaceholderType> varianceTPH = new HashSet<>();
|
||||
varianceTPH = varianceInheritanceConstraintSet(unifyCons);
|
||||
|
||||
/*
|
||||
* PL 2018-11-07 wird in varianceInheritanceConstraintSet erledigt do { //PL 2018-11-05 Huellenbildung Variance auf alle TPHs der Terme auf der jeweiligen //anderen Seite übertragen varianceTPHold = new HashSet<>(varianceTPH); varianceTPH = varianceInheritanceConstraintSet(unifyCons); unifyCons.map( y -> { if ((y.getLhsType() instanceof PlaceholderType) && (y.getRhsType() instanceof PlaceholderType)) { if (((PlaceholderType)y.getLhsType()).getVariance() != 0 &&
|
||||
* ((PlaceholderType)y.getRhsType()).getVariance() == 0) { ((PlaceholderType)y.getRhsType()).setVariance(((PlaceholderType)y.getLhsType( )).getVariance()); } if (((PlaceholderType)y.getLhsType()).getVariance() == 0 && ((PlaceholderType)y.getRhsType()).getVariance() != 0) { ((PlaceholderType)y.getLhsType()).setVariance(((PlaceholderType)y.getRhsType( )).getVariance()); } } return y; } ); } while (!varianceTPHold.equals(varianceTPH));
|
||||
*/
|
||||
|
||||
// Set<Set<UnifyPair>> result = unify.unifySequential(xConsSet, finiteClosure,
|
||||
// logFile, log);
|
||||
// Set<Set<UnifyPair>> result = unify.unify(xConsSet, finiteClosure);
|
||||
List<Set<Constraint<UnifyPair>>> oderConstraints = unifyCons.getOderConstraints()/*
|
||||
* .stream().map(x -> { Set<Set<UnifyPair>> ret = new HashSet<>(); for (Constraint<UnifyPair> y : x) { ret.add(new HashSet<>(y)); } return ret; }).collect(Collectors. toCollection(ArrayList::new))
|
||||
*/;
|
||||
unify.unifyAsync(unifyCons.getUndConstraints(), oderConstraints, finiteClosure, logFile, log, urm, usedTasks);
|
||||
} catch (IOException e) {
|
||||
System.err.println("kein LogFile");
|
||||
}
|
||||
return urm;
|
||||
}
|
||||
|
||||
public List<ResultSet> typeInference(File file) throws ClassNotFoundException, IOException {
|
||||
var sf = sourceFiles.get(file);
|
||||
Set<ClassOrInterface> allClasses = new HashSet<>();// environment.getAllAvailableClasses();
|
||||
allClasses.addAll(getAvailableClasses(sf));
|
||||
allClasses.addAll(sf.getClasses());
|
||||
var newClasses = CompilationEnvironment.loadDefaultPackageClasses(sf.getPkgName(), file, this).stream().map(ASTFactory::createClass).collect(Collectors.toSet());
|
||||
for (var clazz : newClasses) {
|
||||
// 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);
|
||||
}
|
||||
|
||||
final ConstraintSet<Pair> cons = getConstraints(file);
|
||||
Set<Set<UnifyPair>> results = new HashSet<>();
|
||||
try {
|
||||
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.stream().toList(), logFile, classLoader, this);
|
||||
System.out.println(finiteClosure);
|
||||
ConstraintSet<UnifyPair> unifyCons = UnifyTypeFactory.convert(this, cons);
|
||||
System.out.println("xxx1");
|
||||
Function<UnifyPair, UnifyPair> distributeInnerVars = x -> {
|
||||
UnifyType lhs, rhs;
|
||||
if (((lhs = x.getLhsType()) instanceof PlaceholderType) && ((rhs = x.getRhsType()) instanceof PlaceholderType) && (((PlaceholderType) lhs).isInnerType() || ((PlaceholderType) rhs).isInnerType())) {
|
||||
((PlaceholderType) lhs).setInnerType(true);
|
||||
((PlaceholderType) rhs).setInnerType(true);
|
||||
}
|
||||
return x;
|
||||
|
||||
};
|
||||
|
||||
logFile.write("Unify:" + unifyCons.toString());
|
||||
System.out.println("Unify:" + unifyCons.toString());
|
||||
unifyCons = unifyCons.map(distributeInnerVars);
|
||||
logFile.write("\nUnify_distributeInnerVars: " + unifyCons.toString());
|
||||
TypeUnify unify = new TypeUnify();
|
||||
// Set<Set<UnifyPair>> results = new HashSet<>(); Nach vorne gezogen
|
||||
logFile.write("FC:\\" + finiteClosure.toString() + "\n");
|
||||
logFile.write(ASTTypePrinter.print(sf));
|
||||
System.out.println(ASTTypePrinter.print(sf));
|
||||
logFile.flush();
|
||||
|
||||
Set<String> methodParaTypeVarNames = allClasses.stream().map(x -> x.getMethods().stream().map(y -> y.getParameterList().getFormalparalist().stream().filter(z -> z.getType() instanceof TypePlaceholder).map(z -> ((TypePlaceholder) z.getType()).getName()).collect(Collectors.toCollection(HashSet::new))).reduce(new HashSet<String>(), (a, b) -> {
|
||||
a.addAll(b);
|
||||
return a;
|
||||
}, (a, b) -> {
|
||||
a.addAll(b);
|
||||
return a;
|
||||
})).reduce(new HashSet<String>(), (a, b) -> {
|
||||
a.addAll(b);
|
||||
return a;
|
||||
});
|
||||
|
||||
Set<String> constructorParaTypeVarNames = allClasses.stream().map(x -> x.getConstructors().stream().map(y -> y.getParameterList().getFormalparalist().stream().filter(z -> z.getType() instanceof TypePlaceholder).map(z -> ((TypePlaceholder) z.getType()).getName()).collect(Collectors.toCollection(HashSet::new))).reduce(new HashSet<String>(), (a, b) -> {
|
||||
a.addAll(b);
|
||||
return a;
|
||||
}, (a, b) -> {
|
||||
a.addAll(b);
|
||||
return a;
|
||||
})).reduce(new HashSet<String>(), (a, b) -> {
|
||||
a.addAll(b);
|
||||
return a;
|
||||
});
|
||||
|
||||
Set<String> paraTypeVarNames = methodParaTypeVarNames;
|
||||
paraTypeVarNames.addAll(constructorParaTypeVarNames);
|
||||
|
||||
Set<String> returnTypeVarNames = allClasses.stream().map(x -> x.getMethods().stream().filter(y -> y.getReturnType() instanceof TypePlaceholder).map(z -> ((TypePlaceholder) z.getReturnType()).getName()).collect(Collectors.toCollection(HashSet::new))).reduce((a, b) -> {
|
||||
a.addAll(b);
|
||||
return a;
|
||||
}).get();
|
||||
|
||||
Set<String> fieldTypeVarNames = allClasses.stream().map(x -> x.getFieldDecl().stream().filter(y -> y.getReturnType() instanceof TypePlaceholder).map(z -> ((TypePlaceholder) z.getReturnType()).getName()).collect(Collectors.toCollection(HashSet::new))).reduce((a, b) -> {
|
||||
a.addAll(b);
|
||||
return a;
|
||||
}).get();
|
||||
|
||||
returnTypeVarNames.addAll(fieldTypeVarNames);
|
||||
|
||||
unifyCons = unifyCons.map(x -> {
|
||||
// Hier muss ueberlegt werden, ob
|
||||
// 1. alle Argument- und Retuntyp-Variablen in allen UnifyPairs
|
||||
// mit disableWildcardtable() werden.
|
||||
// 2. alle Typvariablen mit Argument- oder Retuntyp-Variablen
|
||||
// in Beziehung auch auf disableWildcardtable() gesetzt werden muessen
|
||||
// PL 2018-04-23
|
||||
if ((x.getLhsType() instanceof PlaceholderType)) {
|
||||
if (paraTypeVarNames.contains(x.getLhsType().getName())) {
|
||||
((PlaceholderType) x.getLhsType()).setVariance((byte) 1);
|
||||
((PlaceholderType) x.getLhsType()).disableWildcardtable();
|
||||
}
|
||||
if (returnTypeVarNames.contains(x.getLhsType().getName())) {
|
||||
((PlaceholderType) x.getLhsType()).setVariance((byte) -1);
|
||||
((PlaceholderType) x.getLhsType()).disableWildcardtable();
|
||||
}
|
||||
}
|
||||
if ((x.getRhsType() instanceof PlaceholderType)) {
|
||||
if (paraTypeVarNames.contains(x.getRhsType().getName())) {
|
||||
((PlaceholderType) x.getRhsType()).setVariance((byte) 1);
|
||||
((PlaceholderType) x.getRhsType()).disableWildcardtable();
|
||||
}
|
||||
if (returnTypeVarNames.contains(x.getRhsType().getName())) {
|
||||
((PlaceholderType) x.getRhsType()).setVariance((byte) -1);
|
||||
((PlaceholderType) x.getRhsType()).disableWildcardtable();
|
||||
}
|
||||
}
|
||||
return x;// HIER DIE JEWEILS RECHT BZW. LINKE SEITE AUF GLEICHE VARIANZ SETZEN WIE DIE
|
||||
// JEWEILS ANDERE SEITE
|
||||
});
|
||||
|
||||
// PL 2020-02-05 alle Oder-Constraints Receiver und Parameter werden auf
|
||||
// variance 1 gesetzt
|
||||
// Es wird davon ausgegangen, dass in OderConstraints in Bedingungen für
|
||||
// Parameter die Typen der Argumente links stehen
|
||||
// und die Typen der Rückgabewerte immer rechts stehen
|
||||
|
||||
/*
|
||||
* unifyCons.getOderConstraints().forEach(z -> z.forEach(y -> y.forEach(x -> { if ((x.getLhsType() instanceof PlaceholderType) && x.getPairOp().compareTo(PairOperator.SMALLERDOT) == 0) { ((PlaceholderType) x.getLhsType()).setVariance((byte)1); } else if ((x.getRhsType() instanceof PlaceholderType) && x.getPairOp().compareTo(PairOperator.EQUALSDOT) == 0) { ((PlaceholderType) x.getRhsType()).setVariance((byte)-1); } })));
|
||||
*/
|
||||
|
||||
System.out.println("Unify nach Oder-Constraints-Anpassung:" + unifyCons.toString());
|
||||
Set<PlaceholderType> varianceTPHold;
|
||||
Set<PlaceholderType> varianceTPH = new HashSet<>();
|
||||
varianceTPH = varianceInheritanceConstraintSet(unifyCons);
|
||||
|
||||
/*
|
||||
* PL 2018-11-07 wird in varianceInheritanceConstraintSet erledigt do { //PL 2018-11-05 Huellenbildung Variance auf alle TPHs der Terme auf der jeweiligen //anderen Seite übertragen varianceTPHold = new HashSet<>(varianceTPH); varianceTPH = varianceInheritanceConstraintSet(unifyCons); unifyCons.map( y -> { if ((y.getLhsType() instanceof PlaceholderType) && (y.getRhsType() instanceof PlaceholderType)) { if (((PlaceholderType)y.getLhsType()).getVariance() != 0 &&
|
||||
* ((PlaceholderType)y.getRhsType()).getVariance() == 0) { ((PlaceholderType)y.getRhsType()).setVariance(((PlaceholderType)y.getLhsType( )).getVariance()); } if (((PlaceholderType)y.getLhsType()).getVariance() == 0 && ((PlaceholderType)y.getRhsType()).getVariance() != 0) { ((PlaceholderType)y.getLhsType()).setVariance(((PlaceholderType)y.getRhsType( )).getVariance()); } } return y; } ); } while (!varianceTPHold.equals(varianceTPH));
|
||||
*/
|
||||
|
||||
// Set<Set<UnifyPair>> result = unify.unifySequential(xConsSet, finiteClosure,
|
||||
// logFile, log);
|
||||
// Set<Set<UnifyPair>> result = unify.unify(xConsSet, finiteClosure);
|
||||
List<Set<Constraint<UnifyPair>>> oderConstraints = unifyCons.getOderConstraints()// .stream().map(x -> {
|
||||
/*
|
||||
* Set<Set<UnifyPair>> ret = new HashSet<>(); for (Constraint<UnifyPair> y : x) { ret.add(new HashSet<>(y)); } return ret; }).collect(Collectors.toCollection(ArrayList::new))
|
||||
*/;
|
||||
if (resultmodel) {
|
||||
/* UnifyResultModel Anfang */
|
||||
UnifyResultModel urm = new UnifyResultModel(cons, finiteClosure);
|
||||
UnifyResultListenerImpl li = new UnifyResultListenerImpl();
|
||||
urm.addUnifyResultListener(li);
|
||||
unify.unifyParallel(unifyCons.getUndConstraints(), oderConstraints, finiteClosure, logFile, log, urm, usedTasks);
|
||||
System.out.println("RESULT Final: " + li.getResults());
|
||||
System.out.println("Constraints for Generated Generics: " + " ???");
|
||||
logFile.write("RES_FINAL: " + li.getResults().toString() + "\n");
|
||||
logFile.flush();
|
||||
return li.getResults();
|
||||
}
|
||||
/* UnifyResultModel End */
|
||||
else {
|
||||
// Set<Set<UnifyPair>> result = unify.unify(unifyCons.getUndConstraints(),
|
||||
// oderConstraints, finiteClosure, logFile, log, new UnifyResultModel(cons,
|
||||
// finiteClosure));
|
||||
Set<Set<UnifyPair>> result = unify.unifyOderConstraints(unifyCons.getUndConstraints(), oderConstraints, finiteClosure, logFile, log, new UnifyResultModel(cons, finiteClosure), usedTasks);
|
||||
System.out.println("RESULT: " + result);
|
||||
logFile.write("RES: " + result.toString() + "\n");
|
||||
logFile.flush();
|
||||
results.addAll(result);
|
||||
|
||||
results = results.stream().map(x -> {
|
||||
Optional<Set<UnifyPair>> res = new RuleSet().subst(x.stream().map(y -> {
|
||||
if (y.getPairOp() == PairOperator.SMALLERDOTWC)
|
||||
y.setPairOp(PairOperator.EQUALSDOT);
|
||||
return y; // alle Paare a <.? b erden durch a =. b ersetzt
|
||||
}).collect(Collectors.toCollection(HashSet::new)));
|
||||
if (res.isPresent()) {// wenn subst ein Erg liefert wurde was veraendert
|
||||
return new TypeUnifyTask().applyTypeUnificationRules(res.get(), finiteClosure);
|
||||
} else
|
||||
return x; // wenn nichts veraendert wurde wird x zurueckgegeben
|
||||
}).collect(Collectors.toCollection(HashSet::new));
|
||||
System.out.println("RESULT Final: " + results);
|
||||
System.out.println("Constraints for Generated Generics: " + " ???");
|
||||
logFile.write("RES_FINAL: " + results.toString() + "\n");
|
||||
logFile.flush();
|
||||
logFile.write("PLACEHOLDERS: " + PlaceholderType.EXISTING_PLACEHOLDERS);
|
||||
logFile.flush();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
System.err.println("kein LogFile");
|
||||
}
|
||||
return results.stream().map((unifyPairs -> new ResultSet(UnifyTypeFactory.convert(unifyPairs, Pair.generateTPHMap(cons))))).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* Vererbt alle Variancen bei Paaren (a <. theta) oder (Theta <. a) wenn a eine Variance !=0 hat auf alle Typvariablen in Theta.
|
||||
*
|
||||
*
|
||||
*/
|
||||
private Set<PlaceholderType> varianceInheritanceConstraintSet(ConstraintSet<UnifyPair> cons) {
|
||||
Set<UnifyPair> eq = cons.getAll();
|
||||
Set<PlaceholderType> usedTPH = new HashSet<>();
|
||||
Set<PlaceholderType> phSet = eq.stream().map(x -> {
|
||||
Set<PlaceholderType> pair = new HashSet<>();
|
||||
if (x.getLhsType() instanceof PlaceholderType)
|
||||
pair.add((PlaceholderType) x.getLhsType());
|
||||
if (x.getRhsType() instanceof PlaceholderType)
|
||||
pair.add((PlaceholderType) x.getRhsType());
|
||||
return pair;
|
||||
}).reduce(new HashSet<>(), (a, b) -> {
|
||||
a.addAll(b);
|
||||
return a;
|
||||
}, (c, d) -> {
|
||||
c.addAll(d);
|
||||
return c;
|
||||
});
|
||||
|
||||
ArrayList<PlaceholderType> phSetVariance = new ArrayList<>(phSet);
|
||||
phSetVariance.removeIf(x -> (x.getVariance() == 0));
|
||||
while (!phSetVariance.isEmpty()) {
|
||||
PlaceholderType a = phSetVariance.remove(0);
|
||||
usedTPH.add(a);
|
||||
// HashMap<PlaceholderType,Integer> ht = new HashMap<>();
|
||||
// ht.put(a, a.getVariance());
|
||||
// ConstraintSet<UnifyPair> eq1 = cons;
|
||||
// eq1.removeIf(x -> !(x.getLhsType() instanceof PlaceholderType &&
|
||||
// ((PlaceholderType)x.getLhsType()).equals(a)));
|
||||
// durch if-Abfrage im foreach geloest
|
||||
cons.forEach(x -> {
|
||||
if (x.getLhsType() instanceof PlaceholderType && ((PlaceholderType) x.getLhsType()).equals(a)) {
|
||||
x.getRhsType().accept(new distributeVariance(), a.getVariance());
|
||||
}
|
||||
});
|
||||
// ` eq1 = new HashSet<>(eq);
|
||||
// eq1.removeIf(x -> !(x.getRhsType() instanceof PlaceholderType &&
|
||||
// ((PlaceholderType)x.getRhsType()).equals(a)));
|
||||
// durch if-Abfrage im foreach geloest
|
||||
cons.forEach(x -> {
|
||||
if (x.getRhsType() instanceof PlaceholderType && ((PlaceholderType) x.getRhsType()).equals(a)) {
|
||||
x.getLhsType().accept(new distributeVariance(), a.getVariance());
|
||||
}
|
||||
});
|
||||
phSetVariance = new ArrayList<>(phSet); // macht vermutlich keinen Sinn PL 2018-10-18, doch, es koennen neue
|
||||
// TPHs mit Variancen dazugekommen sein PL 2018-11-07
|
||||
phSetVariance.removeIf(x -> (x.getVariance() == 0 || usedTPH.contains(x)));
|
||||
}
|
||||
return usedTPH;
|
||||
}
|
||||
|
||||
public final JavaClassRegistry classRegistry = new JavaClassRegistry();
|
||||
|
||||
public record ClassEntry(File classFile, ClassOrInterface cif) {}
|
||||
|
||||
public final Map<JavaClassName, ClassEntry> loadedClasses = new HashMap<>();
|
||||
|
||||
private SourceFile parse(File sourceFile) throws IOException, java.lang.ClassNotFoundException {
|
||||
if (sourceFiles.containsKey(sourceFile)) return sourceFiles.get(sourceFile);
|
||||
SourceFileContext tree = JavaTXParser.parse(sourceFile);
|
||||
environment.addClassesToRegistry(classRegistry, tree, sourceFile, this);
|
||||
SyntaxTreeGenerator generator = new SyntaxTreeGenerator(this, classRegistry, new GenericsRegistry(null), sourceFile.getName());
|
||||
var classes = new ArrayList<ClassOrInterface>();
|
||||
var sf = new SourceFile("", classes, generator.imports);
|
||||
addSourceFile(sourceFile, sf);
|
||||
generator.convert(classes, tree, environment.packageCrawler);
|
||||
sf.setPackageName(generator.pkgName);
|
||||
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
|
||||
@ -698,10 +260,7 @@ public class JavaTXCompiler {
|
||||
addSourceFile(file, sf);
|
||||
generator.convert(classes, tree, environment.packageCrawler);
|
||||
sf.setPackageName(generator.pkgName);
|
||||
var classFiles = generateBytecode(file);
|
||||
|
||||
sf.setGenerated();
|
||||
writeClassFile(classFiles, outputPath != null ? outputPath : new File("."), false);
|
||||
var clazz = classLoader.loadClass(name.toString());
|
||||
var classOrInterface = ASTFactory.createClass(clazz);
|
||||
loadedClasses.put(name, new ClassEntry(new File(outputPath, clazz.getName() + ".class"), classOrInterface));
|
||||
@ -723,85 +282,6 @@ public class JavaTXCompiler {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void generateBytecode() throws ClassNotFoundException, IOException {
|
||||
for (var file : sourceFiles.keySet()) {
|
||||
var sf = sourceFiles.get(file);
|
||||
if (sf.isGenerated()) continue;
|
||||
var classes = generateBytecode(file);
|
||||
sf.setGenerated();
|
||||
writeClassFile(classes, outputPath == null ? file.getParentFile() : outputPath, outputPath == null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param path - output-Directory can be null, then class file output is in the same directory as the parsed source files
|
||||
* @return
|
||||
*/
|
||||
public Map<JavaClassName, byte[]> generateBytecode(File sourceFile) throws ClassNotFoundException, IOException {
|
||||
var sf = sourceFiles.get(sourceFile);
|
||||
if (sf.isGenerated()) return null;
|
||||
List<ResultSet> typeinferenceResult = this.typeInference(sourceFile);
|
||||
var classes = generateBytecode(sf, typeinferenceResult);
|
||||
sf.setGenerated();
|
||||
return classes;
|
||||
}
|
||||
|
||||
private Map<SourceFile, List<GenericsResult>> generatedGenerics = new HashMap<>();
|
||||
|
||||
public Map<SourceFile, List<GenericsResult>> getGeneratedGenerics() {
|
||||
return generatedGenerics;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param outputPath - can be null, then class file output is in the same directory as the parsed source files
|
||||
* @param typeinferenceResult
|
||||
* @throws IOException
|
||||
*/
|
||||
public void generateBytecode(File outputPath, List<ResultSet> typeinferenceResult) throws IOException {
|
||||
for (File f : sourceFiles.keySet()) {
|
||||
HashMap<JavaClassName, byte[]> classFiles = new HashMap<>();
|
||||
SourceFile sf = sourceFiles.get(f);
|
||||
File path = outputPath;
|
||||
if (outputPath == null) {
|
||||
path = f.getParentFile(); // Set path to path of the parsed .jav file
|
||||
}
|
||||
|
||||
var generatedClasses = generateBytecode(sf, typeinferenceResult);
|
||||
writeClassFile(generatedClasses, path, outputPath == null);
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized Map<JavaClassName, byte[]> generateBytecode(SourceFile sf, List<ResultSet> typeInferenceResult) {
|
||||
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), this, converter);
|
||||
var code = codegen.generate();
|
||||
generatedClasses.put(clazz.getClassName(), code);
|
||||
converter.auxiliaries.forEach((name, source) -> {
|
||||
generatedClasses.put(new JavaClassName(name), source);
|
||||
});
|
||||
}
|
||||
generatedGenerics.put(sf, converter.javaGenerics());
|
||||
converter.generateFunNTypes();
|
||||
return generatedClasses;
|
||||
}
|
||||
|
||||
public synchronized void writeClassFile(Map<JavaClassName, byte[]> classFiles, File path, boolean preserveHierarchy) throws IOException {
|
||||
FileOutputStream output;
|
||||
for (JavaClassName name : classFiles.keySet()) {
|
||||
byte[] bytecode = classFiles.get(name);
|
||||
System.out.println("generating " + name + ".class file ...");
|
||||
var subPath = preserveHierarchy ? path : Path.of(path.toString(), name.getPackageName().split("\\.")).toFile();
|
||||
File outputFile = new File(subPath, name.getClassName() + ".class");
|
||||
outputFile.getAbsoluteFile().getParentFile().mkdirs();
|
||||
System.out.println(outputFile);
|
||||
output = new FileOutputStream(outputFile);
|
||||
output.write(bytecode);
|
||||
output.close();
|
||||
System.out.println(name + ".class file generated");
|
||||
}
|
||||
}
|
||||
|
||||
/* PL 2020-03-17 mit TypeExchanger in FCGenerator.java zusammenfuehren */
|
||||
/**
|
||||
|
@ -1,204 +0,0 @@
|
||||
package de.dhbwstuttgart.parser.SyntaxTreeGenerator;
|
||||
|
||||
import de.dhbwstuttgart.core.JavaTXCompiler;
|
||||
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.*;
|
||||
import de.dhbwstuttgart.typeinference.constraints.Pair;
|
||||
import de.dhbwstuttgart.typeinference.unify.model.*;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.antlr.v4.runtime.Token;
|
||||
|
||||
public class FCGenerator {
|
||||
/**
|
||||
* Baut die FiniteClosure aus availableClasses.
|
||||
* Klassen welche nicht in availableClasses vorkommen werden im Java Classpath nachgeschlagen.
|
||||
*
|
||||
* @param availableClasses - Alle geparsten Klassen
|
||||
*/
|
||||
public static Set<UnifyPair> toUnifyFC(JavaTXCompiler compiler, Collection<ClassOrInterface> availableClasses, ClassLoader classLoader) throws ClassNotFoundException {
|
||||
return toFC(availableClasses, classLoader).stream().map(t -> UnifyTypeFactory.convert(compiler, t)).collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
public static Set<Pair> toFC(Collection<ClassOrInterface> availableClasses, ClassLoader classLoader) throws ClassNotFoundException {
|
||||
HashSet<Pair> pairs = new HashSet<>();
|
||||
//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){
|
||||
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, PairOperator.SMALLER);
|
||||
}
|
||||
return null; //kann nicht passieren, da die Methode nur aufgerufen wird wenn cl Functional Interface ist
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Bildet eine Kette vom übergebenen Typ bis hin zum höchsten bekannten Typ
|
||||
* Als Generics werden TPHs benutzt, welche der Unifikationsalgorithmus korrekt interpretieren muss.
|
||||
* Die verwendeten TPHs werden in der Kette nach oben gereicht, so erhält der selbe GTV immer den selben TPH
|
||||
* @param forType
|
||||
* @return
|
||||
*/
|
||||
private static List<Pair> getSuperTypes(ClassOrInterface forType, Collection<ClassOrInterface> availableClasses, ClassLoader classLoader) throws ClassNotFoundException {
|
||||
return getSuperTypes(forType, availableClasses, new HashMap<>(), classLoader);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param forType
|
||||
* @param availableClasses
|
||||
* @param gtvs
|
||||
* @return
|
||||
* @throws ClassNotFoundException
|
||||
*/
|
||||
private static List<Pair> getSuperTypes(ClassOrInterface forType, Collection<ClassOrInterface> availableClasses,
|
||||
HashMap<String, RefTypeOrTPHOrWildcardOrGeneric> gtvs, ClassLoader classLoader) throws ClassNotFoundException {
|
||||
List<RefTypeOrTPHOrWildcardOrGeneric> params = new ArrayList<>();
|
||||
//Die GTVs, die in forType hinzukommen:
|
||||
HashMap<String, RefTypeOrTPHOrWildcardOrGeneric> newGTVs = new HashMap<>();
|
||||
//Generics mit gleichem Namen müssen den selben TPH bekommen
|
||||
for(GenericTypeVar gtv : forType.getGenerics()){
|
||||
if(!gtvs.containsKey(gtv.getName())){
|
||||
TypePlaceholder replacePlaceholder = TypePlaceholder.fresh(new NullToken());
|
||||
gtvs.put(gtv.getName(), replacePlaceholder);
|
||||
newGTVs.put(gtv.getName(), replacePlaceholder);
|
||||
}
|
||||
params.add(gtvs.get(gtv.getName()));
|
||||
}
|
||||
|
||||
|
||||
List<RefType> superClasses = new ArrayList<>();
|
||||
superClasses.add(forType.getSuperClass());
|
||||
superClasses.addAll(forType.getSuperInterfaces());
|
||||
|
||||
List<Pair> retList = new ArrayList<>();
|
||||
for(RefType superType : superClasses){
|
||||
Optional<ClassOrInterface> hasSuperclass = availableClasses.stream().filter(cl -> superType.getName().equals(cl.getClassName())).findAny();
|
||||
ClassOrInterface superClass;
|
||||
if(!hasSuperclass.isPresent()) //Wenn es die Klasse in den available Klasses nicht gibt wird sie im Classpath gesucht. Ansonsten Exception
|
||||
{
|
||||
superClass = ASTFactory.createClass(classLoader.loadClass(superType.getName().toString()));
|
||||
}else{
|
||||
superClass = hasSuperclass.get();
|
||||
}
|
||||
/*
|
||||
Die Parameter der superklasse müssen jetzt nach den Angaben in der Subklasse
|
||||
modifiziert werden
|
||||
Beispie: Matrix<A> extends Vector<Vector<A>>
|
||||
Den ersten Parameter mit Vector<A> austauschen und dort alle Generics zu den Typplaceholdern in gtvs austauschen
|
||||
*/
|
||||
//Hier vermerken, welche Typen in der Superklasse ausgetauscht werden müssen
|
||||
Iterator<GenericTypeVar> itGenParams = superClass.getGenerics().iterator();
|
||||
Iterator<RefTypeOrTPHOrWildcardOrGeneric> itSetParams = superType.getParaList().iterator();
|
||||
while(itSetParams.hasNext()){
|
||||
RefTypeOrTPHOrWildcardOrGeneric setType = itSetParams.next();
|
||||
//In diesem Typ die GTVs durch TPHs und Einsetzungen austauschen:
|
||||
RefTypeOrTPHOrWildcardOrGeneric setSetType = setType.acceptTV(new TypeExchanger(gtvs));
|
||||
newGTVs.put(itGenParams.next().getName(), setSetType);
|
||||
}
|
||||
|
||||
//Für den superType kann man nun zum Austauschen der Generics wieder die gtvs nehmen:
|
||||
//Die newGTVs sind nur für den superClass ClassOrInterface welches möglicherweise per reflection geladen wurde abgestimmt
|
||||
RefTypeOrTPHOrWildcardOrGeneric superRefType = superType.acceptTV(new TypeExchanger(gtvs));
|
||||
|
||||
RefTypeOrTPHOrWildcardOrGeneric t1 = new RefType(forType.getClassName(), params, new NullToken());
|
||||
RefTypeOrTPHOrWildcardOrGeneric t2 = superRefType;
|
||||
|
||||
Pair ret = new Pair(t1, t2, PairOperator.SMALLER);
|
||||
|
||||
List<Pair> superTypes;
|
||||
//Rekursiver Aufruf. Abbruchbedingung ist Object als Superklasse:
|
||||
if(superClass.getClassName().equals(ASTFactory.createObjectClass().getClassName())){
|
||||
superTypes = Arrays.asList(new Pair(ASTFactory.createObjectType(), ASTFactory.createObjectType(), PairOperator.SMALLER));
|
||||
}else{
|
||||
superTypes = getSuperTypes(superClass, availableClasses, newGTVs, classLoader);
|
||||
}
|
||||
|
||||
retList.add(ret);
|
||||
retList.addAll(superTypes);
|
||||
}
|
||||
|
||||
return retList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tauscht die GTVs in einem Typ gegen die entsprechenden Typen in der übergebenen Map aus.
|
||||
*/
|
||||
private static class TypeExchanger implements TypeVisitor<RefTypeOrTPHOrWildcardOrGeneric>{
|
||||
|
||||
private final HashMap<String, RefTypeOrTPHOrWildcardOrGeneric> gtvs;
|
||||
|
||||
TypeExchanger(HashMap<String, RefTypeOrTPHOrWildcardOrGeneric> gtvs){
|
||||
this.gtvs = gtvs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RefTypeOrTPHOrWildcardOrGeneric visit(RefType refType) {
|
||||
List<RefTypeOrTPHOrWildcardOrGeneric> params = new ArrayList<>();
|
||||
for(RefTypeOrTPHOrWildcardOrGeneric param : refType.getParaList()){
|
||||
params.add(param.acceptTV(this));
|
||||
}
|
||||
RefTypeOrTPHOrWildcardOrGeneric ret = new RefType(refType.getName(), params, new NullToken());
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RefTypeOrTPHOrWildcardOrGeneric visit(SuperWildcardType superWildcardType) {
|
||||
throw new DebugException("Dieser Fall darf nicht auftreten");
|
||||
}
|
||||
|
||||
@Override
|
||||
public RefTypeOrTPHOrWildcardOrGeneric visit(TypePlaceholder typePlaceholder) {
|
||||
throw new DebugException("Dieser Fall darf nicht auftreten");
|
||||
}
|
||||
|
||||
@Override
|
||||
public RefTypeOrTPHOrWildcardOrGeneric visit(ExtendsWildcardType extendsWildcardType) {
|
||||
throw new DebugException("Dieser Fall darf nicht auftreten");
|
||||
}
|
||||
|
||||
@Override
|
||||
public RefTypeOrTPHOrWildcardOrGeneric visit(GenericRefType genericRefType) {
|
||||
if(! gtvs.containsKey(genericRefType.getParsedName()))
|
||||
throw new DebugException("Dieser Fall darf nicht auftreten");
|
||||
return gtvs.get(genericRefType.getParsedName());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -1,14 +1,11 @@
|
||||
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.util.*;
|
||||
|
||||
import de.dhbwstuttgart.bytecode.JavaTXSignatureAttribute;
|
||||
import de.dhbwstuttgart.parser.NullToken;
|
||||
import de.dhbwstuttgart.parser.scope.JavaClassName;
|
||||
import de.dhbwstuttgart.syntaxtree.*;
|
||||
@ -21,7 +18,6 @@ import de.dhbwstuttgart.syntaxtree.statement.Statement;
|
||||
import de.dhbwstuttgart.syntaxtree.type.WildcardType;
|
||||
import de.dhbwstuttgart.util.Pair;
|
||||
import org.antlr.v4.runtime.Token;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.objectweb.asm.*;
|
||||
import org.objectweb.asm.signature.SignatureReader;
|
||||
import org.objectweb.asm.signature.SignatureVisitor;
|
||||
@ -42,52 +38,6 @@ public class ASTFactory {
|
||||
var methodSignatures = new HashMap<Pair<String, String>, String>();
|
||||
String classSignature = null;
|
||||
|
||||
// Load class with asm to figure out if there's a JavaTX signature
|
||||
try {
|
||||
var path = jreClass.getName().replace('.', '/') + ".class";
|
||||
var classLoader = jreClass.getClassLoader();
|
||||
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) {
|
||||
String classSignature;
|
||||
|
||||
@Override
|
||||
public void visitAttribute(Attribute attribute) {
|
||||
if (attribute.type.equals("JavaTXSignature")) {
|
||||
classSignature = ((JavaTXSignatureAttribute) attribute).signature;
|
||||
}
|
||||
super.visitAttribute(attribute);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
|
||||
classSignature = signature;
|
||||
super.visit(version, access, name, signature, superName, interfaces);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {
|
||||
|
||||
methodSignatures.put(new Pair<>(name, descriptor), signature);
|
||||
return new MethodVisitor(Opcodes.ASM7) {
|
||||
@Override
|
||||
public void visitAttribute(Attribute attribute) {
|
||||
if (attribute.type.equals("JavaTXSignature")) {
|
||||
methodSignatures.put(new Pair<>(name, descriptor), ((JavaTXSignatureAttribute) attribute).signature);
|
||||
}
|
||||
super.visitAttribute(attribute);
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
classReader.accept(classVisitor, new Attribute[] { new JavaTXSignatureAttribute() }, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
|
||||
classSignature = classVisitor.classSignature;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
// Skip
|
||||
}
|
||||
JavaClassName name = new JavaClassName(jreClass.getName());
|
||||
List<Method> methoden = new ArrayList<>();
|
||||
List<de.dhbwstuttgart.syntaxtree.Constructor> konstruktoren = new ArrayList<>();
|
||||
|
@ -1,296 +0,0 @@
|
||||
package de.dhbwstuttgart.syntaxtree.factory;
|
||||
|
||||
import java.io.Writer;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.*;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
import de.dhbwstuttgart.core.JavaTXCompiler;
|
||||
import de.dhbwstuttgart.exceptions.NotImplementedException;
|
||||
import de.dhbwstuttgart.parser.NullToken;
|
||||
import de.dhbwstuttgart.parser.SourceLoc;
|
||||
import de.dhbwstuttgart.parser.SyntaxTreeGenerator.FCGenerator;
|
||||
import de.dhbwstuttgart.parser.scope.JavaClassName;
|
||||
import de.dhbwstuttgart.syntaxtree.ClassOrInterface;
|
||||
import de.dhbwstuttgart.syntaxtree.GenericTypeVar;
|
||||
import de.dhbwstuttgart.syntaxtree.type.*;
|
||||
import de.dhbwstuttgart.syntaxtree.type.Void;
|
||||
import de.dhbwstuttgart.syntaxtree.type.WildcardType;
|
||||
import de.dhbwstuttgart.typeinference.constraints.ConstraintSet;
|
||||
import de.dhbwstuttgart.typeinference.constraints.Pair;
|
||||
import de.dhbwstuttgart.typeinference.result.PairNoResult;
|
||||
import de.dhbwstuttgart.typeinference.result.PairTPHEqualTPH;
|
||||
import de.dhbwstuttgart.typeinference.result.PairTPHequalRefTypeOrWildcardType;
|
||||
import de.dhbwstuttgart.typeinference.result.PairTPHsmallerTPH;
|
||||
import de.dhbwstuttgart.typeinference.result.ResultPair;
|
||||
import de.dhbwstuttgart.typeinference.unify.model.*;
|
||||
import org.antlr.v4.runtime.Token;
|
||||
|
||||
public class UnifyTypeFactory {
|
||||
|
||||
private static ArrayList<PlaceholderType> PLACEHOLDERS = new ArrayList<>();
|
||||
|
||||
public static FiniteClosure generateFC(List<ClassOrInterface> fromClasses, Writer logFile, ClassLoader classLoader, JavaTXCompiler compiler) throws ClassNotFoundException {
|
||||
/*
|
||||
Die transitive Hülle muss funktionieren.
|
||||
Man darf schreiben List<A> extends AL<A>
|
||||
und Vector<B> extends List<B>
|
||||
hier muss dann aber dennoch die Vererbung V < L < AL
|
||||
hergestellt werden.
|
||||
In einem solchen Vererbungsbaum dürfen die TPH auch die gleichen Namen haben.
|
||||
Generell dürfen sie immer die gleichen Namen haben.
|
||||
TODO: die transitive Hülle bilden
|
||||
*/
|
||||
return new FiniteClosure(FCGenerator.toUnifyFC(compiler, fromClasses, classLoader), logFile, compiler);
|
||||
}
|
||||
|
||||
public static UnifyPair generateSmallerPair(UnifyType tl, UnifyType tr, SourceLoc location){
|
||||
return new UnifyPair(tl, tr, PairOperator.SMALLER, location);
|
||||
}
|
||||
|
||||
public static UnifyPair generateSmallerDotPair(UnifyType tl, UnifyType tr, SourceLoc location){
|
||||
return new UnifyPair(tl, tr, PairOperator.SMALLERDOT, location);
|
||||
}
|
||||
|
||||
public static UnifyPair generateSmallNotEqualDotPair(UnifyType tl, UnifyType tr, SourceLoc location){
|
||||
return new UnifyPair(tl, tr, PairOperator.SMALLERNEQDOT, location);
|
||||
}
|
||||
|
||||
public static UnifyPair generateEqualDotPair(UnifyType tl, UnifyType tr, SourceLoc location){
|
||||
return new UnifyPair(tl, tr, PairOperator.EQUALSDOT, location);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert from
|
||||
* ASTType -> UnifyType
|
||||
*/
|
||||
public static UnifyType convert(JavaTXCompiler compiler, RefTypeOrTPHOrWildcardOrGeneric t, Boolean innerType){
|
||||
if (t instanceof GenericRefType){
|
||||
return UnifyTypeFactory.convert(compiler, (GenericRefType)t, innerType);
|
||||
} else if (t instanceof TypePlaceholder){
|
||||
return UnifyTypeFactory.convert(compiler, (TypePlaceholder)t, innerType);
|
||||
} else if (t instanceof ExtendsWildcardType){
|
||||
return UnifyTypeFactory.convert(compiler, (ExtendsWildcardType)t, innerType);
|
||||
} else if (t instanceof SuperWildcardType) {
|
||||
return UnifyTypeFactory.convert(compiler, (SuperWildcardType) t, innerType);
|
||||
} else if (t instanceof RefType){
|
||||
return UnifyTypeFactory.convert(compiler, (RefType)t, innerType);
|
||||
}
|
||||
//Es wurde versucht ein Typ umzuwandeln, welcher noch nicht von der Factory abgedeckt ist
|
||||
throw new NotImplementedException("Der Typ "+t+" kann nicht umgewandelt werden");
|
||||
}
|
||||
|
||||
public static UnifyType convert(JavaTXCompiler compiler, RefType t, Boolean innerType){
|
||||
//Check if it is a FunN Type:
|
||||
Pattern p = Pattern.compile("Fun(\\d+)[$][$]");
|
||||
Matcher m = p.matcher(t.getName().toString());
|
||||
boolean b = m.matches();
|
||||
if(b){
|
||||
Integer N = Integer.valueOf(m.group(1));
|
||||
if((N + 1) == t.getParaList().size()){
|
||||
return convertFunN(compiler, t.getParaList(), false);
|
||||
}
|
||||
}
|
||||
UnifyType ret;
|
||||
List<UnifyType> params = new ArrayList<>();
|
||||
if (t.getParaList() != null) {
|
||||
for (RefTypeOrTPHOrWildcardOrGeneric pT : t.getParaList()) {
|
||||
params.add(UnifyTypeFactory.convert(compiler, pT, true));
|
||||
}
|
||||
}
|
||||
|
||||
var clazz = compiler.getClass(t.getName());
|
||||
if (clazz != null && clazz.isInterface() && clazz.isFunctionalInterface()) {
|
||||
var method = clazz.getMethods().stream().filter(x -> Modifier.isAbstract(x.modifier)).findFirst().orElseThrow();
|
||||
var methodParams = method.getParameterList().getFormalparalist().stream().map(x -> convert(compiler, x.getType(), true)).toList();
|
||||
var generics = StreamSupport.stream(clazz.getGenerics().spliterator(), false).map(GenericTypeVar::getName).toList();
|
||||
return new FunInterfaceType(t.getName().toString(), new TypeParams(params), methodParams, convert(compiler, method.getReturnType(), true), generics);
|
||||
}
|
||||
|
||||
return new ReferenceType(t.getName().toString(),new TypeParams(params));
|
||||
}
|
||||
|
||||
public static UnifyType convertFunN(JavaTXCompiler compiler, List<RefTypeOrTPHOrWildcardOrGeneric> paraList, Boolean innerType){
|
||||
UnifyType ret;
|
||||
List<UnifyType> params = new ArrayList<>();
|
||||
if(paraList != null && paraList.size() > 0){
|
||||
for(RefTypeOrTPHOrWildcardOrGeneric pT : paraList){
|
||||
params.add(UnifyTypeFactory.convert(compiler, pT, false));
|
||||
}
|
||||
}
|
||||
ret = FunNType.getFunNType(new TypeParams(params));
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static UnifyType convert(JavaTXCompiler compiler, TypePlaceholder tph, Boolean innerType){
|
||||
if (tph.getName().equals("AFR")) {
|
||||
System.out.println("XXX"+innerType);
|
||||
}
|
||||
PlaceholderType ntph = new PlaceholderType(tph.getName());
|
||||
ntph.setVariance(tph.getVariance());
|
||||
ntph.setOrCons(tph.getOrCons());
|
||||
int in = PLACEHOLDERS.indexOf(ntph);
|
||||
if (in == -1) {
|
||||
PLACEHOLDERS.add(ntph);
|
||||
ntph.setInnerType(innerType);
|
||||
return ntph;
|
||||
}
|
||||
else {
|
||||
PlaceholderType oldpht = PLACEHOLDERS.get(in);
|
||||
oldpht.setInnerType(oldpht.isInnerType() || innerType);
|
||||
return oldpht;
|
||||
}
|
||||
}
|
||||
|
||||
public static UnifyType convert(JavaTXCompiler compiler, GenericRefType t, Boolean innerType){
|
||||
return new ReferenceType(t.getParsedName(), true);
|
||||
}
|
||||
|
||||
public static UnifyType convert(JavaTXCompiler compiler, WildcardType t, Boolean innerType){
|
||||
if(t.isExtends())
|
||||
return new ExtendsType(UnifyTypeFactory.convert(compiler, t.getInnerType(), false));
|
||||
else if(t.isSuper())
|
||||
return new SuperType(UnifyTypeFactory.convert(compiler, t.getInnerType(), false));
|
||||
else throw new NotImplementedException();
|
||||
}
|
||||
|
||||
|
||||
public static ConstraintSet<UnifyPair> convert(JavaTXCompiler compiler, ConstraintSet<Pair> constraints) {
|
||||
return constraints.map(c -> UnifyTypeFactory.convert(compiler, c));
|
||||
}
|
||||
|
||||
//NEVER USED
|
||||
//public static Constraint<UnifyPair> convert(Constraint<Pair> constraint){
|
||||
// Constraint<UnifyPair> unifyPairConstraint = constraint.stream()
|
||||
// .map(UnifyTypeFactory::convert)
|
||||
// .collect(Collectors.toCollection( () -> new Constraint<UnifyPair> (constraint.isInherited(), convert(constraint.getExtendConstraint()))));
|
||||
// return unifyPairConstraint;
|
||||
//}
|
||||
|
||||
public static UnifyPair convert(JavaTXCompiler compiler, Pair p) {
|
||||
UnifyPair ret = null;
|
||||
if(p.GetOperator().equals(PairOperator.SMALLERDOT)) {
|
||||
ret = generateSmallerDotPair(UnifyTypeFactory.convert(compiler, p.TA1, false)
|
||||
, UnifyTypeFactory.convert(compiler, p.TA2, false), p.getLocation());
|
||||
//return ret;
|
||||
}else if(p.GetOperator().equals(PairOperator.SMALLERNEQDOT)) {
|
||||
ret = generateSmallNotEqualDotPair(UnifyTypeFactory.convert(compiler, p.TA1, false)
|
||||
, UnifyTypeFactory.convert(compiler, p.TA2, false), p.getLocation());
|
||||
//return ret;
|
||||
}else if(p.GetOperator().equals(PairOperator.EQUALSDOT)) {
|
||||
ret = generateEqualDotPair(UnifyTypeFactory.convert(compiler, p.TA1, false)
|
||||
, UnifyTypeFactory.convert(compiler, p.TA2, false), p.getLocation());
|
||||
//return ret;
|
||||
}else if(p.GetOperator().equals(PairOperator.SMALLER)){
|
||||
ret = generateSmallerPair(UnifyTypeFactory.convert(compiler, p.TA1, false),
|
||||
UnifyTypeFactory.convert(compiler, p.TA2, false), p.getLocation());
|
||||
}else throw new NotImplementedException();
|
||||
UnifyType lhs, rhs;
|
||||
if (((lhs = ret.getLhsType()) instanceof PlaceholderType)
|
||||
&& ((PlaceholderType)lhs).isWildcardable()
|
||||
&& (rhs = ret.getLhsType()) instanceof PlaceholderType) {
|
||||
if (lhs.getName().equals("AQ")) {
|
||||
System.out.println("");
|
||||
}
|
||||
((PlaceholderType)rhs).enableWildcardtable();
|
||||
}
|
||||
|
||||
if (((rhs = ret.getLhsType()) instanceof PlaceholderType)
|
||||
&& ((PlaceholderType)rhs).isWildcardable()
|
||||
&& (lhs = ret.getLhsType()) instanceof PlaceholderType) {
|
||||
if (rhs.getName().equals("AQ")) {
|
||||
System.out.println("");
|
||||
}
|
||||
((PlaceholderType)lhs).enableWildcardtable();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert from
|
||||
* UnifyType -> ASTType
|
||||
*/
|
||||
public static Set<ResultPair> convert(Set<UnifyPair> unifyPairSet, Map<String,TypePlaceholder> tphs) {
|
||||
return unifyPairSet.stream().map(
|
||||
unifyPair -> convert(unifyPair, tphs))
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
public static ResultPair convert(UnifyPair mp, Map<String,TypePlaceholder> tphs) {
|
||||
if (mp == null) { return null;} //kann bei basePairs passieren
|
||||
RefTypeOrTPHOrWildcardOrGeneric tl = UnifyTypeFactory.convert(mp.getLhsType(), tphs);
|
||||
RefTypeOrTPHOrWildcardOrGeneric tr = UnifyTypeFactory.convert(mp.getRhsType(), tphs);
|
||||
if(tl instanceof TypePlaceholder){
|
||||
if(tr instanceof TypePlaceholder) {
|
||||
|
||||
if(mp.getPairOp().equals(PairOperator.EQUALSDOT)) {
|
||||
return new PairTPHEqualTPH((TypePlaceholder)tl, (TypePlaceholder)tr);
|
||||
//Einfach ignorieren TODO: Das hier muss ausgebessert werden:
|
||||
//return new PairTPHequalRefTypeOrWildcardType((TypePlaceholder)tl, ASTFactory.createObjectType());
|
||||
}else{
|
||||
return new PairTPHsmallerTPH((TypePlaceholder)tl, (TypePlaceholder)tr, convert(mp.getBasePair(), tphs));
|
||||
}
|
||||
}else if(tr instanceof RefType){
|
||||
return new PairTPHequalRefTypeOrWildcardType((TypePlaceholder)tl, (RefType) tr);
|
||||
}else if(tr instanceof WildcardType){
|
||||
return new PairTPHequalRefTypeOrWildcardType((TypePlaceholder)tl, (WildcardType) tr);
|
||||
}else if(tr instanceof GenericRefType){
|
||||
return new PairTPHequalRefTypeOrWildcardType((TypePlaceholder)tl, (GenericRefType) tr);
|
||||
}else throw new NotImplementedException();
|
||||
}else return new PairNoResult(tl, tr);//throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public static RefTypeOrTPHOrWildcardOrGeneric convert(ReferenceType t, Map<String,TypePlaceholder> tphs) {
|
||||
if(JavaClassName.Void.equals(t.getName()))return new Void(new NullToken());
|
||||
if (t.isGenTypeVar()) return new GenericRefType(t.getName(),new NullToken());
|
||||
RefType ret = new RefType(new JavaClassName(t.getName()),convert(t.getTypeParams(), tphs),new NullToken());
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static RefTypeOrTPHOrWildcardOrGeneric convert(FunNType t, Map<String,TypePlaceholder> tphs) {
|
||||
RefType ret = new RefType(new JavaClassName(t.getName()), convert(t.getTypeParams(), tphs), new NullToken());
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static RefTypeOrTPHOrWildcardOrGeneric convert(SuperType t, Map<String,TypePlaceholder> tphs) {
|
||||
RefTypeOrTPHOrWildcardOrGeneric innerType = convert(t.getSuperedType(), tphs);
|
||||
return new SuperWildcardType(innerType, new NullToken());
|
||||
}
|
||||
|
||||
public static RefTypeOrTPHOrWildcardOrGeneric convert(ExtendsType t, Map<String,TypePlaceholder> tphs) {
|
||||
RefTypeOrTPHOrWildcardOrGeneric innerType = convert(t.getExtendedType(), tphs);
|
||||
return new ExtendsWildcardType(innerType, new NullToken());
|
||||
}
|
||||
|
||||
public static RefTypeOrTPHOrWildcardOrGeneric convert(PlaceholderType t, Map<String,TypePlaceholder> tphs) {
|
||||
TypePlaceholder ret = tphs.get(t.getName());
|
||||
if(ret == null){ //Dieser TPH wurde vom Unifikationsalgorithmus erstellt
|
||||
ret = TypePlaceholder.fresh(new NullToken());
|
||||
tphs.put(t.getName(), ret);
|
||||
}
|
||||
ret.setVariance(t.getVariance());
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static RefTypeOrTPHOrWildcardOrGeneric convert(UnifyType t, Map<String,TypePlaceholder> tphs) {
|
||||
if(t instanceof FunNType)return convert((FunNType) t, tphs);
|
||||
if(t instanceof ReferenceType)return convert((ReferenceType) t, tphs);
|
||||
if(t instanceof SuperType)return convert((SuperType) t, tphs);
|
||||
if(t instanceof ExtendsType)return convert((ExtendsType) t, tphs);
|
||||
if(t instanceof PlaceholderType)return convert((PlaceholderType) t, tphs);
|
||||
throw new NotImplementedException("Der Typ "+t+" kann nicht umgewandelt werden");
|
||||
}
|
||||
|
||||
private static List<RefTypeOrTPHOrWildcardOrGeneric> convert(TypeParams typeParams, Map<String,TypePlaceholder> tphs) {
|
||||
List<RefTypeOrTPHOrWildcardOrGeneric> ret = new ArrayList<>();
|
||||
for(UnifyType uT : typeParams){
|
||||
RefTypeOrTPHOrWildcardOrGeneric toAdd = convert(uT, tphs);
|
||||
ret.add(toAdd);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
}
|
@ -2,9 +2,6 @@
|
||||
package de.dhbwstuttgart.syntaxtree.statement;
|
||||
|
||||
import de.dhbwstuttgart.syntaxtree.StatementVisitor;
|
||||
import de.dhbwstuttgart.typeinference.assumptions.TypeInferenceBlockInformation;
|
||||
import de.dhbwstuttgart.typeinference.constraints.ConstraintSet;
|
||||
import de.dhbwstuttgart.typeinference.unify.model.PairOperator;
|
||||
import org.antlr.v4.runtime.Token;
|
||||
|
||||
/*
|
||||
|
@ -1,18 +1,9 @@
|
||||
package de.dhbwstuttgart.syntaxtree.statement;
|
||||
|
||||
import de.dhbwstuttgart.exceptions.TypeinferenceException;
|
||||
import de.dhbwstuttgart.syntaxtree.StatementVisitor;
|
||||
import de.dhbwstuttgart.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric;
|
||||
import de.dhbwstuttgart.typeinference.assumptions.FieldAssumption;
|
||||
import de.dhbwstuttgart.typeinference.assumptions.TypeInferenceBlockInformation;
|
||||
import de.dhbwstuttgart.typeinference.constraints.Constraint;
|
||||
import de.dhbwstuttgart.typeinference.constraints.ConstraintSet;
|
||||
import de.dhbwstuttgart.typeinference.unify.model.PairOperator;
|
||||
import org.antlr.v4.runtime.Token;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class FieldVar extends Expression {
|
||||
|
||||
public final String fieldVarName;
|
||||
|
@ -1,15 +1,7 @@
|
||||
package de.dhbwstuttgart.syntaxtree.statement;
|
||||
|
||||
import de.dhbwstuttgart.exceptions.TypeinferenceException;
|
||||
import de.dhbwstuttgart.syntaxtree.*;
|
||||
import de.dhbwstuttgart.syntaxtree.type.RefType;
|
||||
import de.dhbwstuttgart.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric;
|
||||
import de.dhbwstuttgart.typeinference.assumptions.TypeInferenceBlockInformation;
|
||||
import de.dhbwstuttgart.typeinference.constraints.Constraint;
|
||||
import de.dhbwstuttgart.typeinference.constraints.ConstraintSet;
|
||||
import de.dhbwstuttgart.typeinference.assumptions.MethodAssumption;
|
||||
import de.dhbwstuttgart.typeinference.constraints.Pair;
|
||||
import de.dhbwstuttgart.typeinference.unify.model.PairOperator;
|
||||
import org.antlr.v4.runtime.Token;
|
||||
|
||||
import de.dhbwstuttgart.syntaxtree.type.TypePlaceholder;
|
||||
|
@ -1,25 +1,10 @@
|
||||
package de.dhbwstuttgart.syntaxtree.statement;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import de.dhbwstuttgart.exceptions.TypeinferenceException;
|
||||
import de.dhbwstuttgart.parser.NullToken;
|
||||
import de.dhbwstuttgart.syntaxtree.ClassOrInterface;
|
||||
import de.dhbwstuttgart.syntaxtree.Method;
|
||||
import de.dhbwstuttgart.syntaxtree.StatementVisitor;
|
||||
import de.dhbwstuttgart.syntaxtree.type.RefType;
|
||||
import de.dhbwstuttgart.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric;
|
||||
import de.dhbwstuttgart.syntaxtree.type.TypePlaceholder;
|
||||
import de.dhbwstuttgart.typeinference.assumptions.MethodAssumption;
|
||||
import de.dhbwstuttgart.typeinference.assumptions.TypeInferenceBlockInformation;
|
||||
import de.dhbwstuttgart.typeinference.constraints.Constraint;
|
||||
import de.dhbwstuttgart.typeinference.constraints.ConstraintSet;
|
||||
import de.dhbwstuttgart.typeinference.constraints.Pair;
|
||||
import de.dhbwstuttgart.typeinference.unify.model.PairOperator;
|
||||
import org.antlr.v4.runtime.Token;
|
||||
import de.dhbwstuttgart.exceptions.NotImplementedException;
|
||||
|
||||
|
||||
public class NewClass extends MethodCall
|
||||
|
@ -1,602 +0,0 @@
|
||||
package de.dhbwstuttgart.target.generate;
|
||||
|
||||
import de.dhbwstuttgart.bytecode.CodeGenException;
|
||||
import de.dhbwstuttgart.bytecode.FunNGenerator;
|
||||
import de.dhbwstuttgart.core.JavaTXCompiler;
|
||||
import de.dhbwstuttgart.environment.ByteArrayClassLoader;
|
||||
import de.dhbwstuttgart.environment.IByteArrayClassLoader;
|
||||
import de.dhbwstuttgart.parser.NullToken;
|
||||
import de.dhbwstuttgart.parser.scope.JavaClassName;
|
||||
import de.dhbwstuttgart.syntaxtree.*;
|
||||
import de.dhbwstuttgart.syntaxtree.Record;
|
||||
import de.dhbwstuttgart.syntaxtree.factory.ASTFactory;
|
||||
import de.dhbwstuttgart.syntaxtree.statement.*;
|
||||
import de.dhbwstuttgart.syntaxtree.type.*;
|
||||
import de.dhbwstuttgart.target.tree.*;
|
||||
import de.dhbwstuttgart.target.tree.expression.*;
|
||||
import de.dhbwstuttgart.target.tree.type.*;
|
||||
import de.dhbwstuttgart.typeinference.result.*;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* @author dholle
|
||||
*/
|
||||
public class ASTToTargetAST {
|
||||
|
||||
record SignaturePair(TypePlaceholder signature, RefTypeOrTPHOrWildcardOrGeneric parameter) {};
|
||||
record SignaturePairTarget(TargetType signature, TargetType parameter) {}
|
||||
|
||||
public static RefType OBJECT = ASTFactory.createObjectType(); // TODO It would be better if I could call this directly but the hashcode seems to change
|
||||
|
||||
protected List<Generics> all;
|
||||
public Generics generics;
|
||||
final Map<ClassOrInterface, Set<GenericTypeVar>> userDefinedGenerics = new HashMap<>();
|
||||
final Map<Method, Set<SignaturePair>> tphsInMethods = new HashMap<>();
|
||||
private Method currentMethod;
|
||||
|
||||
public final JavaTXCompiler compiler;
|
||||
|
||||
public List<GenericsResult> txGenerics() {
|
||||
return all.stream().map(generics -> new GenericsResult(generics.txGenerics)).toList();
|
||||
}
|
||||
|
||||
public List<GenericsResult> javaGenerics() {
|
||||
return all.stream().map(generics -> new GenericsResult(generics.javaGenerics)).toList();
|
||||
}
|
||||
|
||||
public TargetExpression convert(Pattern pattern) {
|
||||
var converter = new StatementToTargetExpression(this);
|
||||
pattern.accept(converter);
|
||||
return converter.result;
|
||||
}
|
||||
|
||||
public record Generics(JavaGenerics javaGenerics, TxGenerics txGenerics) {
|
||||
}
|
||||
|
||||
|
||||
public IByteArrayClassLoader classLoader;
|
||||
protected SourceFile sourceFile;
|
||||
|
||||
public ASTToTargetAST(List<ResultSet> resultSets) {
|
||||
this(null, resultSets);
|
||||
}
|
||||
public ASTToTargetAST(JavaTXCompiler compiler, List<ResultSet> resultSets) {
|
||||
this(compiler, resultSets, null, new ByteArrayClassLoader());
|
||||
}
|
||||
|
||||
public ASTToTargetAST(JavaTXCompiler compiler, List<ResultSet> resultSets, SourceFile sourceFile, IByteArrayClassLoader classLoader) {
|
||||
this.compiler = compiler;
|
||||
this.classLoader = classLoader;
|
||||
this.sourceFile = sourceFile;
|
||||
|
||||
all = new ArrayList<>();
|
||||
for (var set : resultSets) {
|
||||
all.add(new Generics(new JavaGenerics(this, set), new TxGenerics(this, set)));
|
||||
}
|
||||
this.generics = all.get(0);
|
||||
}
|
||||
|
||||
public void addSignaturePair(TypePlaceholder signature, RefTypeOrTPHOrWildcardOrGeneric parameter) {
|
||||
var set = tphsInMethods.getOrDefault(currentMethod, new HashSet<>());
|
||||
set.add(new SignaturePair(signature, parameter));
|
||||
tphsInMethods.put(currentMethod, set);
|
||||
}
|
||||
|
||||
Optional<Method> findMethod(ClassOrInterface owner, String name, List<TargetType> argumentList) {
|
||||
Optional<Method> method = Optional.empty();
|
||||
while (method.isEmpty()) {
|
||||
method = owner.getMethods().stream().filter(m -> m.name.equals(name) && parameterEquals(m.getParameterList(), argumentList)).findFirst();
|
||||
if (owner.getClassName().toString().equals("java.lang.Object")) break;
|
||||
owner = compiler.getClass(owner.getSuperClass().getName());
|
||||
}
|
||||
return method;
|
||||
}
|
||||
|
||||
Optional<Constructor> findConstructor(ClassOrInterface owner, List<TargetType> argumentList) {
|
||||
return owner.getConstructors().stream().filter(c -> parameterEquals(c.getParameterList(), argumentList)).findFirst();
|
||||
}
|
||||
|
||||
boolean parameterEquals(ParameterList parameterList, List<TargetType> arguments) {
|
||||
var pars = parameterList.getFormalparalist();
|
||||
if (pars.size() != arguments.size())
|
||||
return false;
|
||||
|
||||
for (var i = 0; i < pars.size(); i++) {
|
||||
var type1 = convert(pars.get(i).getType(), generics.javaGenerics);
|
||||
var type2 = arguments.get(i);
|
||||
if (type1 instanceof TargetGenericType)
|
||||
return true;
|
||||
if (TargetType.toPrimitive(type2).equals(type1))
|
||||
return true;
|
||||
if (!type1.equals(type2))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Set<TargetGeneric> convert(Set<GenerateGenerics.Pair> result, GenerateGenerics generics) {
|
||||
return result.stream().map(p -> {
|
||||
if (p instanceof GenerateGenerics.PairLT pair) {
|
||||
return new TargetGeneric(pair.left.resolve().getName(), convert(pair.right.resolve(), generics));
|
||||
} else if (p instanceof GenerateGenerics.PairEQ pair) {
|
||||
return new TargetGeneric(pair.left.resolve().getName(), convert(pair.right, generics));
|
||||
} else {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}).collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
public List<TargetGeneric> convert(GenericTypeVar typeVar, GenerateGenerics generics) {
|
||||
var ret = new ArrayList<TargetGeneric>();
|
||||
for (var bound : typeVar.getBounds()) {
|
||||
ret.add(new TargetGeneric(typeVar.getName(), generics.getTargetType(bound)));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public List<List<TargetMethod>> groupOverloads(ClassOrInterface input, List<Method> methods) {
|
||||
var res = new ArrayList<List<TargetMethod>>();
|
||||
for (var method : methods) {
|
||||
// Convert all methods
|
||||
var methodsWithTphs = convert(input, method);
|
||||
// Then check for methods with the same signature
|
||||
var mapOfSignatures = new HashMap<TargetMethod.Signature, List<MethodWithTphs>>();
|
||||
for (var m : methodsWithTphs) {
|
||||
var methodsWithSameSignature = mapOfSignatures.getOrDefault(m.method.signature(), new ArrayList<>());
|
||||
methodsWithSameSignature.add(m);
|
||||
mapOfSignatures.put(m.method.signature(), methodsWithSameSignature);
|
||||
}
|
||||
|
||||
var resMethods = new HashSet<TargetMethod>();
|
||||
for (var methodsWithSignature : mapOfSignatures.values()) {
|
||||
outer: for (var m1 : methodsWithSignature) {
|
||||
for (var m2 : methodsWithSignature) {
|
||||
for (var i = 0; i < m1.args.size(); i++) {
|
||||
var arg1 = m1.args.get(i);
|
||||
var arg2 = m2.args.get(i);
|
||||
if (arg1.parameter.equals(arg2.parameter)) {
|
||||
if (isSupertype(arg1.signature, arg2.signature) &&
|
||||
!arg1.signature.equals(arg2.signature)) continue outer;
|
||||
}
|
||||
}
|
||||
}
|
||||
resMethods.add(m1.method);
|
||||
}
|
||||
}
|
||||
res.add(resMethods.stream().toList());
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
public TargetStructure convert(ClassOrInterface input) {
|
||||
Set<TargetGeneric> javaGenerics = new HashSet<>();
|
||||
Set<TargetGeneric> txGenerics = new HashSet<>();
|
||||
|
||||
var genericsIter = input.getGenerics().iterator();
|
||||
if (genericsIter.hasNext()) {
|
||||
// Add empty set of generics to cache so that it doesn't try to calculate it later
|
||||
var userDefinedGenerics = new HashSet<GenericTypeVar>();
|
||||
this.userDefinedGenerics.put(input, userDefinedGenerics);
|
||||
while (genericsIter.hasNext()) {
|
||||
var next = genericsIter.next();
|
||||
userDefinedGenerics.add(next);
|
||||
// TODO Support multiple bounds
|
||||
javaGenerics.add(new TargetGeneric(next.getName(), convert(next.getBounds().get(0))));
|
||||
}
|
||||
} else {
|
||||
this.userDefinedGenerics.put(input, new HashSet<>());
|
||||
// Generate generics only if there are no user defined ones
|
||||
javaGenerics = convert(generics.javaGenerics.generics(input), generics.javaGenerics);
|
||||
txGenerics = convert(generics.txGenerics.generics(input), generics.txGenerics);
|
||||
}
|
||||
|
||||
TargetBlock fieldInitializer = null;
|
||||
if (input.getfieldInitializations().isPresent())
|
||||
fieldInitializer = convert(input.getfieldInitializations().get().block);
|
||||
TargetBlock finalFieldInitializer = fieldInitializer;
|
||||
|
||||
var superInterfaces = input.getSuperInterfaces().stream().map(clazz -> convert(clazz, generics.javaGenerics)).toList();
|
||||
var constructors = input.getConstructors().stream().map(constructor -> this.convert(input, constructor, finalFieldInitializer)).flatMap(List::stream).toList();
|
||||
var fields = input.getFieldDecl().stream().map(this::convert).toList();
|
||||
var methods = groupOverloads(input, input.getMethods()).stream().flatMap(List::stream).toList();
|
||||
|
||||
TargetMethod staticConstructor = null;
|
||||
if (input.getStaticInitializer().isPresent())
|
||||
staticConstructor = this.convert(input, input.getStaticInitializer().get()).stream().findFirst().orElseThrow().method;
|
||||
|
||||
if (input instanceof Record)
|
||||
return new TargetRecord(input.getModifiers(), input.getClassName(), javaGenerics, txGenerics, superInterfaces, constructors, staticConstructor, fields, methods);
|
||||
else if (input.isInterface())
|
||||
return new TargetInterface(input.getModifiers(), input.getClassName(), javaGenerics, txGenerics, methods, superInterfaces, staticConstructor);
|
||||
else return new TargetClass(input.getModifiers(), input.getClassName(), convert(input.getSuperClass(), generics.javaGenerics), javaGenerics, txGenerics, superInterfaces, constructors, staticConstructor, fields, methods);
|
||||
}
|
||||
|
||||
public List<MethodParameter> convert(ParameterList input, GenerateGenerics generics) {
|
||||
return input.getFormalparalist().stream().map(param ->
|
||||
new MethodParameter((TargetPattern) convert(param))
|
||||
).toList();
|
||||
}
|
||||
|
||||
private boolean hasGeneric(Set<TargetGeneric> generics, GenericRefType type) {
|
||||
return generics.stream().anyMatch(g -> g.name().equals(type.getParsedName()));
|
||||
}
|
||||
|
||||
private Set<TargetGeneric> collectMethodGenerics(ClassOrInterface clazz, GenerateGenerics generateGenerics, Set<GenerateGenerics.Pair> generics, Method input) {
|
||||
var convertedGenerics = new HashSet<>(convert(generics, generateGenerics));
|
||||
outer: for (GenericTypeVar typeVar : input.getGenerics()) {
|
||||
for (var classGeneric : clazz.getGenerics()) {
|
||||
if (classGeneric.equals(typeVar)) {
|
||||
continue outer;
|
||||
}
|
||||
}
|
||||
convertedGenerics.addAll(convert(typeVar, generateGenerics));
|
||||
}
|
||||
/*
|
||||
* var returnType = sigma.getType(input.getReturnType(), equality); if ((returnType instanceof GenericRefType refType) && !hasGeneric(convertedGenerics, refType)) { convertedGenerics.add(new TargetGeneric(refType.getParsedName(), convert(OBJECT))); } for (var param : input.getParameterList()) { var type = sigma.getType(param.getType(), equality); if (type instanceof GenericRefType refType && !hasGeneric(convertedGenerics, refType)) { convertedGenerics.add(new
|
||||
* TargetGeneric(refType.getParsedName(), convert(OBJECT))); } }
|
||||
*/
|
||||
|
||||
return convertedGenerics;
|
||||
}
|
||||
|
||||
private List<TargetConstructor> convert(ClassOrInterface currentClass, Constructor input, TargetBlock fieldInitializer) {
|
||||
generics = all.get(0);
|
||||
List<TargetConstructor> result = new ArrayList<>();
|
||||
Set<List<MethodParameter>> parameterSet = new HashSet<>();
|
||||
this.currentMethod = input;
|
||||
|
||||
for (var s : all) {
|
||||
generics = s;
|
||||
var javaGenerics = this.generics.javaGenerics.generics(currentClass, input);
|
||||
var txGenerics = this.generics.txGenerics.generics(currentClass, input);
|
||||
List<MethodParameter> params = convert(input.getParameterList(), this.generics.javaGenerics);
|
||||
if (parameterSet.stream().noneMatch(p -> p.equals(params))) {
|
||||
List<MethodParameter> txParams = convert(input.getParameterList(), this.generics.txGenerics);
|
||||
var javaMethodGenerics = collectMethodGenerics(currentClass, generics.javaGenerics(), javaGenerics, input);
|
||||
var txMethodGenerics = collectMethodGenerics(currentClass, generics.txGenerics(), txGenerics, input);
|
||||
|
||||
result.add(new TargetConstructor(input.modifier, javaMethodGenerics, txMethodGenerics, params, txParams, convert(input.block), fieldInitializer));
|
||||
parameterSet.add(params);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private String encodeName(String name, ParameterList params) {
|
||||
var res = new StringBuilder();
|
||||
res.append(name);
|
||||
res.append('$');
|
||||
for (var param : params.getFormalparalist()) {
|
||||
if (param instanceof RecordPattern rp) {
|
||||
res.append(FunNGenerator.encodeType(convert(param.getType())));
|
||||
for (var pattern : rp.getSubPattern()) {
|
||||
res.append(FunNGenerator.encodeType(convert(pattern.getType())));
|
||||
}
|
||||
}
|
||||
}
|
||||
return res.toString();
|
||||
}
|
||||
|
||||
private List<TargetMethod> convert(ClassOrInterface clazz, List<Method> overloadedMethods) {
|
||||
if (overloadedMethods.size() == 1) {
|
||||
return convert(clazz, overloadedMethods.getFirst()).stream().map(m -> m.method()).toList();
|
||||
}
|
||||
var methods = new ArrayList<Method>();
|
||||
for (var method : overloadedMethods) {
|
||||
var newMethod = new Method(
|
||||
method.modifier,
|
||||
method.name,
|
||||
//encodeName(method.name, method.getParameterList()),
|
||||
method.getReturnType(),
|
||||
method.getParameterList(),
|
||||
method.block,
|
||||
method.getGenerics(),
|
||||
method.getOffset()
|
||||
);
|
||||
methods.add(newMethod);
|
||||
}
|
||||
|
||||
// TODO Record overloading
|
||||
/*var template = overloadedMethods.get(0);
|
||||
|
||||
var pParams = new ArrayList<Pattern>();
|
||||
var i = 0;
|
||||
for (var par : template.getParameterList()) {
|
||||
pParams.add(switch (par) {
|
||||
case RecordPattern rp -> new RecordPattern(rp.getSubPattern(), "par" + i, rp.getType(), new NullToken());
|
||||
default -> par;
|
||||
});
|
||||
i++;
|
||||
}
|
||||
var params = new ParameterList(pParams, new NullToken());
|
||||
|
||||
var statements = new ArrayList<Statement>();
|
||||
statements.add(new Return(makeRecordSwitch(template.getReturnType(), params, res), new NullToken()));
|
||||
var block = new Block(statements, new NullToken());
|
||||
var entryPoint = new Method(template.modifier, template.name, template.getReturnType(), params, block, template.getGenerics(), new NullToken());
|
||||
|
||||
res.add(entryPoint); // TODO*/
|
||||
var res = new ArrayList<TargetMethod>();
|
||||
for (var method : methods) {
|
||||
var overloads = convert(clazz, method);
|
||||
for (var m : overloads) {
|
||||
var overload = m.method;
|
||||
if (res.contains(overload)) throw new CodeGenException("Duplicate method found: " + overload.name() + " with signature " + overload.signature().getSignature());
|
||||
res.add(overload);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
private Expression makeRecordSwitch(RefTypeOrTPHOrWildcardOrGeneric returnType, ParameterList params, List<Method> overloadedMethods) {
|
||||
var param = params.getFormalparalist().get(0);
|
||||
assert param instanceof RecordPattern; // TODO
|
||||
|
||||
var cases = new ArrayList<SwitchBlock>();
|
||||
for (var method : overloadedMethods) {
|
||||
var statements = new ArrayList<Statement>();
|
||||
/*statements.add(new MethodCall(
|
||||
method.getReturnType(), new ExpressionReceiver(new This(new NullToken())), method.name,
|
||||
params,
|
||||
));*/
|
||||
|
||||
var block = new Block(statements, new NullToken());
|
||||
var labels = new ArrayList<SwitchLabel>();
|
||||
cases.add(new SwitchBlock(labels, block, true, new NullToken()));
|
||||
}
|
||||
var swtch = new Switch(new LocalVar("par0", param.getType(), new NullToken()), cases, returnType, false, new NullToken());
|
||||
|
||||
return swtch;
|
||||
}
|
||||
|
||||
private Optional<Method> findSuperMethodToOverride(ClassOrInterface currentClass, String name, List<MethodParameter> params) {
|
||||
var superClass = compiler.getClass(currentClass.getSuperClass().getName());
|
||||
var methodStream = superClass.getMethods().stream();
|
||||
for (var superInterface : currentClass.getSuperInterfaces()) {
|
||||
methodStream = Stream.concat(methodStream, compiler.getClass(superInterface.getName()).getMethods().stream());
|
||||
}
|
||||
|
||||
return methodStream.filter(m -> {
|
||||
if (!m.name.equals(name)) return false;
|
||||
var sParams = m.getParameterList();
|
||||
if (sParams.getFormalparalist().size() != params.size()) return false;
|
||||
for (var i = 0; i < params.size(); i++) {
|
||||
var a = TargetType.toPrimitive(params.get(i).pattern().type());
|
||||
var b = convert(sParams.getFormalparalist().get(i).getType());
|
||||
if (!Objects.equals(a, b)) return false;
|
||||
}
|
||||
return true;
|
||||
}).findFirst();
|
||||
}
|
||||
|
||||
record MethodWithTphs(TargetMethod method, List<SignaturePairTarget> args) {}
|
||||
|
||||
private List<MethodWithTphs> convert(ClassOrInterface currentClass, Method method) {
|
||||
generics = all.getFirst();
|
||||
List<MethodWithTphs> result = new ArrayList<>();
|
||||
this.currentMethod = method;
|
||||
|
||||
for (var s : all) {
|
||||
generics = s;
|
||||
var javaGenerics = this.generics.javaGenerics.generics(currentClass, method);
|
||||
var txGenerics = this.generics.txGenerics.generics(currentClass, method);
|
||||
List<MethodParameter> params = convert(method.getParameterList(), this.generics.javaGenerics);
|
||||
var returnType = convert(method.getReturnType(), this.generics.javaGenerics);
|
||||
var superMethod = findSuperMethodToOverride(currentClass, method.getName(), params);
|
||||
if (superMethod.isPresent()) {
|
||||
// If we find a super method to override, use its parameters and return types
|
||||
var newReturnType = convert(superMethod.get().getReturnType(), this.generics.javaGenerics);
|
||||
if (newReturnType instanceof TargetPrimitiveType && TargetType.toPrimitive(returnType).equals(newReturnType)) {
|
||||
returnType = newReturnType;
|
||||
params = convert(superMethod.get().getParameterList(), method.getParameterList(), this.generics.javaGenerics);
|
||||
}
|
||||
}
|
||||
|
||||
List<MethodParameter> txParams = convert(method.getParameterList(), this.generics.txGenerics);
|
||||
|
||||
var javaMethodGenerics = collectMethodGenerics(currentClass, generics.javaGenerics(), javaGenerics, method);
|
||||
var txMethodGenerics = collectMethodGenerics(currentClass, generics.txGenerics(), txGenerics, method);
|
||||
|
||||
var javaSignature = new TargetMethod.Signature(javaMethodGenerics, params, returnType);
|
||||
var txSignature = new TargetMethod.Signature(txMethodGenerics, txParams, convert(method.getReturnType(), this.generics.txGenerics));
|
||||
var newMethod = new TargetMethod(method.modifier, method.name, convert(method.block), javaSignature, txSignature);
|
||||
|
||||
var concreteParams = tphsInMethods.getOrDefault(method, new HashSet<>()).stream().map(sig -> new SignaturePairTarget(convert(sig.signature), convert(sig.parameter))).toList();
|
||||
|
||||
result.add(new MethodWithTphs(newMethod, concreteParams));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private List<MethodParameter> convert(ParameterList superList, ParameterList paraList, JavaGenerics generics) {
|
||||
var list = new ArrayList<MethodParameter>();
|
||||
for (var i = 0; i < paraList.getFormalparalist().size(); i++) {
|
||||
var param = paraList.getParameterAt(i);
|
||||
list.add(new MethodParameter((TargetPattern) convert(param)).withType(convert(superList.getParameterAt(i).getType(), generics)));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
protected TargetSwitch.Case convert(SwitchBlock block) {
|
||||
return new TargetSwitch.Case(block.getLabels().stream().map(this::convert).toList(), convert((Block) block), block.isExpression);
|
||||
}
|
||||
|
||||
protected TargetBlock convert(Block block) {
|
||||
if (block == null) return null;
|
||||
return new TargetBlock(block.statements.stream().map(this::convert).toList());
|
||||
}
|
||||
|
||||
protected TargetBlock convertWrapInBlock(Expression expression) {
|
||||
var res = convert(expression);
|
||||
if (!(res instanceof TargetBlock))
|
||||
return new TargetBlock(List.of(res));
|
||||
return (TargetBlock) res;
|
||||
}
|
||||
|
||||
protected TargetExpression convert(Expression expr) {
|
||||
var converter = new StatementToTargetExpression(this);
|
||||
expr.accept(converter);
|
||||
return converter.result;
|
||||
}
|
||||
|
||||
private TargetField convert(Field input) {
|
||||
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) {
|
||||
return convert(input, generics.javaGenerics);
|
||||
}
|
||||
|
||||
private static void collectArguments(TargetSpecializedType tspec, List<TargetType> newParams) {
|
||||
for (var i = 0; i < tspec.params().size(); i++) {
|
||||
var param = tspec.params().get(i);
|
||||
if (param instanceof TargetSpecializedType fn) {
|
||||
collectArguments(tspec, newParams);
|
||||
} else {
|
||||
newParams.add(param);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static TargetType flattenFunNType(List<TargetType> params, FunNGenerator.GenericParameters gep) {
|
||||
var newParams = new ArrayList<TargetType>();
|
||||
for (TargetType param : params) {
|
||||
if (param instanceof TargetSpecializedType fn) {
|
||||
collectArguments(fn, newParams);
|
||||
} else {
|
||||
newParams.add(param);
|
||||
}
|
||||
}
|
||||
var filteredParams = new ArrayList<TargetType>();
|
||||
for (var i = 0; i < newParams.size(); i++) {
|
||||
if (i < gep.inParams.size() && gep.inParams.get(i) != null)
|
||||
filteredParams.add(newParams.get(i));
|
||||
}
|
||||
return TargetFunNType.fromParams(params, filteredParams, gep.getReturnType() != null ? 1 : 0);
|
||||
}
|
||||
|
||||
private boolean isSubtype(TargetType test, TargetType other) {
|
||||
var testClass = compiler.getClass(new JavaClassName(test.name()));
|
||||
var otherClass = compiler.getClass(new JavaClassName(other.name()));
|
||||
if (testClass == null) return false;
|
||||
while (testClass != null) {
|
||||
if (testClass.equals(otherClass)) return true;
|
||||
if (testClass.getClassName().equals(new JavaClassName("java.lang.Object"))) break;
|
||||
testClass = compiler.getClass(testClass.getSuperClass().getName());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean isSupertype(TargetType test, TargetType other) {
|
||||
return isSubtype(other, test);
|
||||
}
|
||||
|
||||
private boolean isSubtype(FunNGenerator.GenericParameters test, FunNGenerator.GenericParameters other) {
|
||||
if (test.getArguments().size() != other.getArguments().size()) return false;
|
||||
if (!isSubtype(test.getReturnType(), other.getReturnType())) return false;
|
||||
for (int i = 0; i < test.getArguments().size(); i++) {
|
||||
var arg1 = test.getArguments().get(i);
|
||||
var arg2 = other.getArguments().get(i);
|
||||
if (!isSupertype(arg1, arg2)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void generateFunNTypes() {
|
||||
for (var entry : usedFunN.entrySet()) {
|
||||
var gep = entry.getValue();
|
||||
var superInterfaces = usedFunN.values().stream()
|
||||
.filter(g -> !g.equals(gep))
|
||||
.filter(genericParameters -> isSubtype(gep, genericParameters))
|
||||
.map(FunNGenerator::getSpecializedClassName)
|
||||
.toList();
|
||||
|
||||
var code = FunNGenerator.generateSpecializedBytecode(gep, superInterfaces);
|
||||
|
||||
try {
|
||||
classLoader.findClass(entry.getKey());
|
||||
} catch (ClassNotFoundException e) {
|
||||
try {
|
||||
classLoader.loadClass(code);
|
||||
} catch (LinkageError ignored) {}
|
||||
}
|
||||
auxiliaries.put(entry.getKey(), code);
|
||||
}
|
||||
}
|
||||
|
||||
protected TargetType convert(RefTypeOrTPHOrWildcardOrGeneric input, GenerateGenerics generics) {
|
||||
return input.acceptTV(new TypeVisitor<>() {
|
||||
@Override
|
||||
public TargetType visit(RefType refType) {
|
||||
var name = refType.getName().toString();
|
||||
if (name.equals("void"))
|
||||
return null;
|
||||
if (refType.isPrimitive()) {
|
||||
return TargetType.toPrimitive(refType);
|
||||
}
|
||||
|
||||
var params = refType.getParaList().stream().map(type -> {
|
||||
return convert(type, generics);
|
||||
}).toList();
|
||||
|
||||
if (name.matches("Fun\\d+\\$\\$")) { // TODO This seems like a bad idea
|
||||
var returnType = FunNGenerator.getReturnType(params);
|
||||
var className = FunNGenerator.getSpecializedClassName(FunNGenerator.getArguments(params), returnType);
|
||||
if (!usedFunNSuperTypes.contains(params.size())) {
|
||||
usedFunNSuperTypes.add(params.size());
|
||||
var code = FunNGenerator.generateSuperBytecode(params.size() - 1, returnType != null ? 1 : 0);
|
||||
var superClassName = FunNGenerator.getSuperClassName(params.size() - 1, returnType != null ? 1 : 0);
|
||||
try {
|
||||
classLoader.findClass(superClassName);
|
||||
} catch (ClassNotFoundException e) {
|
||||
try {
|
||||
classLoader.loadClass(code);
|
||||
} catch (LinkageError ignored) {}
|
||||
}
|
||||
auxiliaries.put(superClassName, code);
|
||||
}
|
||||
FunNGenerator.GenericParameters gep = null;
|
||||
if (!usedFunN.containsKey(className)) {
|
||||
gep = new FunNGenerator.GenericParameters(params, returnType != null ? 1 : 0);
|
||||
usedFunN.put(className, gep);
|
||||
} else {
|
||||
gep = usedFunN.get(className);
|
||||
}
|
||||
return flattenFunNType(params, gep);
|
||||
}
|
||||
return new TargetRefType(name, params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TargetType visit(SuperWildcardType superWildcardType) {
|
||||
return new TargetSuperWildcard(convert(superWildcardType.getInnerType(), generics));
|
||||
}
|
||||
|
||||
@Override
|
||||
public TargetType visit(TypePlaceholder typePlaceholder) {
|
||||
return generics.getTargetType(typePlaceholder);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TargetType visit(ExtendsWildcardType extendsWildcardType) {
|
||||
return new TargetExtendsWildcard(convert(extendsWildcardType.getInnerType(), generics));
|
||||
}
|
||||
|
||||
@Override
|
||||
public TargetType visit(GenericRefType genericRefType) {
|
||||
return new TargetGenericType(genericRefType.getParsedName());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
@ -1,24 +0,0 @@
|
||||
package de.dhbwstuttgart.target.generate;
|
||||
|
||||
import de.dhbwstuttgart.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric;
|
||||
import de.dhbwstuttgart.syntaxtree.type.TypePlaceholder;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public record Bound(boolean isOnMethod, RefTypeOrTPHOrWildcardOrGeneric bound) {
|
||||
public static Bound onMethod(String tph) {
|
||||
return new Bound(true, TypePlaceholder.of(tph));
|
||||
}
|
||||
|
||||
public static Bound onMethod(RefTypeOrTPHOrWildcardOrGeneric bound) {
|
||||
return new Bound(true, bound);
|
||||
}
|
||||
|
||||
public static Bound onClass(String tph) {
|
||||
return new Bound(false, TypePlaceholder.of(tph));
|
||||
}
|
||||
|
||||
public static Bound onClass(RefTypeOrTPHOrWildcardOrGeneric bound) {
|
||||
return new Bound(false, bound);
|
||||
}
|
||||
}
|
@ -1,52 +0,0 @@
|
||||
package de.dhbwstuttgart.target.generate;
|
||||
|
||||
import de.dhbwstuttgart.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric;
|
||||
import de.dhbwstuttgart.syntaxtree.type.TypePlaceholder;
|
||||
|
||||
import java.util.AbstractList;
|
||||
import java.util.List;
|
||||
|
||||
public class BoundsList extends AbstractList<Bound> {
|
||||
private final List<Bound> bounds;
|
||||
public final RefTypeOrTPHOrWildcardOrGeneric base;
|
||||
|
||||
public BoundsList(RefTypeOrTPHOrWildcardOrGeneric base, List<Bound> bounds) {
|
||||
this.base = base;
|
||||
this.bounds = bounds;
|
||||
}
|
||||
|
||||
public BoundsList(List<Bound> bounds) {
|
||||
this(null, bounds);
|
||||
}
|
||||
|
||||
public BoundsList(Bound... bounds) {
|
||||
this(null, List.of(bounds));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Bound get(int index) {
|
||||
return bounds.get(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return bounds.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (!(other instanceof BoundsList right)) return false;
|
||||
if (size() != right.size()) return false;
|
||||
for (var i = 0; i < size(); i++) {
|
||||
var l = get(i);
|
||||
var r = right.get(i);
|
||||
if (l.isOnMethod() != r.isOnMethod()) return false;
|
||||
if (i == size() - 1) {
|
||||
if (!(l.bound() instanceof TypePlaceholder)) {
|
||||
if (!(l.bound().equals(r.bound()))) return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
@ -1,104 +0,0 @@
|
||||
package de.dhbwstuttgart.target.generate;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class CycleFinder {
|
||||
private CycleFinder() {}
|
||||
|
||||
static Set<GenerateGenerics.TPH> allNodes(Set<? extends GenerateGenerics.Pair> input) {
|
||||
return input.stream()
|
||||
.filter(GenerateGenerics.PairLT.class::isInstance)
|
||||
.map(GenerateGenerics.PairLT.class::cast)
|
||||
.flatMap(pair -> Stream.of(pair.left, pair.right)).collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
static Set<GenerateGenerics.TPH> outgoingEdgesOf(GenerateGenerics.TPH tph, Set<? extends GenerateGenerics.Pair> input) {
|
||||
return input.stream()
|
||||
.filter(GenerateGenerics.PairLT.class::isInstance)
|
||||
.map(GenerateGenerics.PairLT.class::cast)
|
||||
.filter(pair -> pair.left.equals(tph))
|
||||
.map(pair -> pair.right).collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
static boolean containsEdge(GenerateGenerics.TPH a, GenerateGenerics.TPH b, Set<? extends GenerateGenerics.Pair> input) {
|
||||
return input.stream()
|
||||
.filter(GenerateGenerics.PairLT.class::isInstance)
|
||||
.map(GenerateGenerics.PairLT.class::cast)
|
||||
.anyMatch(pair -> pair.left.equals(a) && pair.right.equals(b));
|
||||
}
|
||||
|
||||
// Tiernan simple cycles algorithm
|
||||
// Adapted from https://github.com/jgrapht/jgrapht/blob/master/jgrapht-core/src/main/java/org/jgrapht/alg/cycle/TiernanSimpleCycles.java
|
||||
static Set<List<GenerateGenerics.TPH>> findCycles(Set<? extends GenerateGenerics.Pair> input) {
|
||||
Map<GenerateGenerics.TPH, Integer> indices = new HashMap<>();
|
||||
List<GenerateGenerics.TPH> path = new ArrayList<>();
|
||||
Set<GenerateGenerics.TPH> pathSet = new HashSet<>();
|
||||
Map<GenerateGenerics.TPH, Set<GenerateGenerics.TPH>> blocked = new HashMap<>();
|
||||
Set<List<GenerateGenerics.TPH>> cycles = new HashSet<>();
|
||||
|
||||
int index = 0;
|
||||
for (var tph : allNodes(input)) {
|
||||
blocked.put(tph, new HashSet<>());
|
||||
indices.put(tph, index++);
|
||||
}
|
||||
|
||||
var vertexIterator = allNodes(input).iterator();
|
||||
if (!vertexIterator.hasNext()) return cycles;
|
||||
|
||||
GenerateGenerics.TPH startOfPath = null;
|
||||
GenerateGenerics.TPH endOfPath = vertexIterator.next();
|
||||
GenerateGenerics.TPH temp = null;
|
||||
int endIndex = 0;
|
||||
boolean extensionFound = false;
|
||||
path.add(endOfPath);
|
||||
pathSet.add(endOfPath);
|
||||
|
||||
while (true) {
|
||||
do {
|
||||
extensionFound = false;
|
||||
for (GenerateGenerics.TPH n : outgoingEdgesOf(endOfPath, input)) {
|
||||
int cmp = indices.get(n).compareTo(indices.get(path.get(0)));
|
||||
if ((cmp > 0) && !pathSet.contains(n) && !blocked.get(endOfPath).contains(n)) {
|
||||
path.add(n);
|
||||
pathSet.add(n);
|
||||
endOfPath = n;
|
||||
extensionFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} while (extensionFound);
|
||||
|
||||
startOfPath = path.get(0);
|
||||
if (containsEdge(endOfPath, startOfPath, input)) {
|
||||
List<GenerateGenerics.TPH> cycle = new ArrayList<>(path);
|
||||
cycles.add(cycle);
|
||||
}
|
||||
if (path.size() > 1) {
|
||||
blocked.get(endOfPath).clear();
|
||||
endIndex = path.size() - 1;
|
||||
path.remove(endIndex);
|
||||
pathSet.remove(endOfPath);
|
||||
--endIndex;
|
||||
temp = endOfPath;
|
||||
endOfPath = path.get(endIndex);
|
||||
blocked.get(endOfPath).add(temp);
|
||||
continue;
|
||||
}
|
||||
if (vertexIterator.hasNext()) {
|
||||
path.clear();
|
||||
pathSet.clear();
|
||||
endOfPath = vertexIterator.next();
|
||||
path.add(endOfPath);
|
||||
pathSet.add(endOfPath);
|
||||
for (GenerateGenerics.TPH tph : blocked.keySet()) {
|
||||
blocked.get(tph).clear();
|
||||
}
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return cycles;
|
||||
}
|
||||
}
|
@ -1,976 +0,0 @@
|
||||
package de.dhbwstuttgart.target.generate;
|
||||
|
||||
import de.dhbwstuttgart.parser.NullToken;
|
||||
import de.dhbwstuttgart.syntaxtree.ClassOrInterface;
|
||||
import de.dhbwstuttgart.syntaxtree.Constructor;
|
||||
import de.dhbwstuttgart.syntaxtree.GenericTypeVar;
|
||||
import de.dhbwstuttgart.syntaxtree.Method;
|
||||
import de.dhbwstuttgart.syntaxtree.statement.*;
|
||||
import de.dhbwstuttgart.syntaxtree.type.*;
|
||||
import de.dhbwstuttgart.syntaxtree.type.Void;
|
||||
import de.dhbwstuttgart.target.tree.type.TargetGenericType;
|
||||
import de.dhbwstuttgart.target.tree.type.TargetType;
|
||||
import de.dhbwstuttgart.typeinference.result.PairTPHEqualTPH;
|
||||
import de.dhbwstuttgart.typeinference.result.PairTPHequalRefTypeOrWildcardType;
|
||||
import de.dhbwstuttgart.typeinference.result.PairTPHsmallerTPH;
|
||||
import de.dhbwstuttgart.typeinference.result.ResultSet;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public abstract class GenerateGenerics {
|
||||
|
||||
private final ASTToTargetAST astToTargetAST;
|
||||
|
||||
public class TPH {
|
||||
private final TypePlaceholder wrap;
|
||||
|
||||
TPH(TypePlaceholder wrap) {
|
||||
this.wrap = wrap;
|
||||
}
|
||||
|
||||
public TypePlaceholder resolve() {
|
||||
return equality.getOrDefault(wrap, wrap);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
TPH tph = (TPH) o;
|
||||
return Objects.equals(resolve(), tph.resolve());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(resolve());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return resolve().getName();
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class Pair {
|
||||
public final TPH left;
|
||||
|
||||
Pair(TPH left) {
|
||||
this.left = left;
|
||||
}
|
||||
|
||||
public abstract RefTypeOrTPHOrWildcardOrGeneric resolveRight();
|
||||
}
|
||||
|
||||
public class PairLT extends Pair {
|
||||
public final TPH right;
|
||||
|
||||
PairLT(TPH left, TPH right) {
|
||||
super(left);
|
||||
this.right = right;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
PairLT pairLT = (PairLT) o;
|
||||
return Objects.equals(right, pairLT.right) && Objects.equals(left, pairLT.left);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(right, left);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RefTypeOrTPHOrWildcardOrGeneric resolveRight() {
|
||||
return right.resolve();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "(" + left + " < " + right + ")";
|
||||
}
|
||||
}
|
||||
|
||||
public class PairEQ extends Pair {
|
||||
public final RefType right;
|
||||
|
||||
PairEQ(TPH left, RefType right) {
|
||||
super(left);
|
||||
this.right = right;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
PairEQ pairLT = (PairEQ) o;
|
||||
return Objects.equals(right, pairLT.right) && Objects.equals(left, pairLT.left);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(right, left);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RefTypeOrTPHOrWildcardOrGeneric resolveRight() {
|
||||
return right;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "(" + left + " = " + right + ")";
|
||||
}
|
||||
}
|
||||
|
||||
final Map<Method, Set<Pair>> computedGenericsOfMethods = new HashMap<>();
|
||||
final Map<ClassOrInterface, Set<Pair>> computedGenericsOfClasses = new HashMap<>();
|
||||
|
||||
final Map<Method, Set<TPH>> usedTPHsOfMethods = new HashMap<>();
|
||||
final Map<Method, Set<Pair>> familyOfMethods = new HashMap<>();
|
||||
|
||||
final Set<PairLT> simplifiedConstraints = new HashSet<>();
|
||||
final Map<TPH, RefTypeOrTPHOrWildcardOrGeneric> concreteTypes = new HashMap<>();
|
||||
final Map<TypePlaceholder, TypePlaceholder> equality = new HashMap<>();
|
||||
|
||||
GenerateGenerics(ASTToTargetAST astToTargetAST, ResultSet constraints) {
|
||||
this.astToTargetAST = astToTargetAST;
|
||||
for (var constraint : constraints.results) {
|
||||
if (constraint instanceof PairTPHsmallerTPH p) {
|
||||
System.out.println(p.left + " " + p.left.getVariance());
|
||||
simplifiedConstraints.add(new PairLT(new TPH(p.left), new TPH(p.right)));
|
||||
} else if (constraint instanceof PairTPHEqualTPH p) {
|
||||
equality.put(p.getLeft(), p.getRight());
|
||||
} else if (constraint instanceof PairTPHequalRefTypeOrWildcardType p) {
|
||||
System.out.println(p.left + " = " + p.right);
|
||||
concreteTypes.put(new TPH(p.left), p.right);
|
||||
}
|
||||
}
|
||||
|
||||
System.out.println("Simplified constraints: " + simplifiedConstraints);
|
||||
}
|
||||
|
||||
Set<TPH> findTypeVariables(RefTypeOrTPHOrWildcardOrGeneric type) {
|
||||
var result = new HashSet<TPH>();
|
||||
if (type instanceof TypePlaceholder tph) {
|
||||
var nTph = new TPH(tph);
|
||||
if (concreteTypes.containsKey(nTph)) {
|
||||
result.addAll(findTypeVariables(concreteTypes.get(nTph)));
|
||||
return result;
|
||||
}
|
||||
result.add(nTph);
|
||||
} else if (type instanceof RefType refType) {
|
||||
for (var t : refType.getParaList())
|
||||
result.addAll(findTypeVariables(t));
|
||||
} else if (type instanceof ExtendsWildcardType wildcardType) {
|
||||
result.addAll(findTypeVariables(wildcardType.getInnerType()));
|
||||
} else if (type instanceof SuperWildcardType wildcardType) {
|
||||
result.addAll(findTypeVariables(wildcardType.getInnerType()));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
boolean containsRelation(Set<Pair> result, PairLT pair) {
|
||||
// Check if both the right and the left are already part of a relation
|
||||
var containsLeft = false;
|
||||
for (var pair2 : result) {
|
||||
if (pair2.left.equals(pair.left)) {
|
||||
containsLeft = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
var containsRight = false;
|
||||
for (var pair2 : result)
|
||||
if (pair2 instanceof PairLT plt) {
|
||||
if (plt.right.equals(pair.right)) {
|
||||
containsRight = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return containsLeft && containsRight;
|
||||
}
|
||||
|
||||
void addToPairs(Set<Pair> input, Pair pair) {
|
||||
if (pair instanceof PairLT plt) {
|
||||
input.removeIf(pair2 -> {
|
||||
if (pair2 instanceof PairEQ peq) {
|
||||
return peq.left.equals(plt.left) && peq.right.equals(ASTToTargetAST.OBJECT);
|
||||
}
|
||||
return false;
|
||||
});
|
||||
} else if (input.stream().anyMatch(p -> p.left.equals(pair.left))) {
|
||||
return;
|
||||
}
|
||||
|
||||
input.add(pair);
|
||||
}
|
||||
|
||||
void addToEquality(TypePlaceholder from, TypePlaceholder to, Set<TPH> referenced) {
|
||||
for (var entry : new HashSet<>(equality.entrySet())) {
|
||||
if (entry.getValue().equals(from)) {
|
||||
equality.remove(entry.getKey());
|
||||
equality.put(entry.getKey(), to);
|
||||
}
|
||||
}
|
||||
System.out.println(from + " -> " + to + " " + from.getVariance());
|
||||
//from.setVariance(to.getVariance());
|
||||
equality.put(from, to);
|
||||
referenced.remove(new TPH(from));
|
||||
referenced.add(new TPH(to));
|
||||
}
|
||||
|
||||
Set<Pair> transitiveClosure(Set<? extends Pair> generics) {
|
||||
Set<Pair> all = new HashSet<>(generics);
|
||||
Set<Pair> toAdd = new HashSet<>();
|
||||
int sizeBefore;
|
||||
do {
|
||||
sizeBefore = all.size();
|
||||
toAdd.clear();
|
||||
for (var g1 : all) {
|
||||
for (var g2 : all) {
|
||||
if (g1 instanceof PairLT pair && g2 instanceof PairLT pair2) {
|
||||
if (pair2.left.equals(pair.right))
|
||||
toAdd.add(new PairLT(pair.left, pair2.right));
|
||||
}
|
||||
}
|
||||
}
|
||||
all.addAll(toAdd);
|
||||
} while (sizeBefore < all.size());
|
||||
return all;
|
||||
}
|
||||
|
||||
private void methodFindConstraints(
|
||||
ClassOrInterface owner, Method method,
|
||||
Set<TPH> typeVariables,
|
||||
Set<TPH> typeVariablesOfClass,
|
||||
Set<Pair> result
|
||||
) {
|
||||
var userDefinedGenericsOfClass = astToTargetAST.userDefinedGenerics.get(owner);
|
||||
|
||||
// Type variables with bounds that are also type variables of the method
|
||||
for (var typeVariable : new HashSet<>(typeVariables)) {
|
||||
if (classHasGeneric(userDefinedGenericsOfClass, typeVariablesOfClass, typeVariable))
|
||||
continue;
|
||||
for (var pair : simplifiedConstraints) {
|
||||
if (pair.left.equals(typeVariable) && typeVariables.contains(pair.right)) {
|
||||
addToPairs(result, new PairLT(pair.left, pair.right));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (method.block != null)
|
||||
method.block.accept(new TracingStatementVisitor() {
|
||||
|
||||
private RefTypeOrTPHOrWildcardOrGeneric superType = new de.dhbwstuttgart.syntaxtree.type.Void(new NullToken());
|
||||
|
||||
@Override
|
||||
public void visit(MethodCall methodCall) {
|
||||
//Anfang es werden Paare von TPHs gespeichert, die bei den Generated Generics ueber die Methodengrenzen hinweg
|
||||
//betrachtet werden muessen
|
||||
//Definition 7.2 (Family of generated generics). T1 <. R1 <.^∗ R2 <. T2
|
||||
Set<TPH> T1s =
|
||||
methodCall.getArgumentList()
|
||||
.getArguments()
|
||||
.stream()
|
||||
.map(TypableStatement::getType)
|
||||
.collect(Collectors.toCollection(HashSet::new))
|
||||
.stream().filter(TypePlaceholder.class::isInstance)
|
||||
.map(TypePlaceholder.class::cast)
|
||||
.map(TPH::new)
|
||||
.collect(Collectors.toCollection(HashSet::new));
|
||||
Set<TPH> T2s = new HashSet<>();
|
||||
findTphs(superType, T2s);
|
||||
|
||||
System.out.println("T1s: " + T1s + " T2s: " + T2s);
|
||||
//Ende
|
||||
|
||||
superType = methodCall.receiverType;
|
||||
methodCall.receiver.accept(this);
|
||||
for (int i = 0; i < methodCall.arglist.getArguments().size(); i++) {
|
||||
superType = methodCall.arglist.getArguments().get(i).getType();
|
||||
methodCall.arglist.getArguments().get(i).accept(this);
|
||||
}
|
||||
|
||||
if (methodCall.receiver instanceof ExpressionReceiver expressionReceiver) {
|
||||
if (expressionReceiver.expr instanceof This) {
|
||||
var optMethod = astToTargetAST.findMethod(owner, methodCall.name, methodCall.signatureArguments().stream().map(astToTargetAST::convert).toList());
|
||||
if (optMethod.isEmpty()) return;
|
||||
var method2 = optMethod.get();
|
||||
System.out.println("In: " + method.getName() + " Method: " + method2.getName());
|
||||
var generics = family(owner, method2);
|
||||
|
||||
// transitive and
|
||||
var all = transitiveClosure(generics);
|
||||
// reflexive
|
||||
var toAdd = new HashSet<Pair>();
|
||||
for (var generic : all) {
|
||||
toAdd.add(new PairLT(generic.left, generic.left));
|
||||
}
|
||||
all.addAll(toAdd);
|
||||
|
||||
HashSet<PairLT> newPairs = new HashSet<>();
|
||||
|
||||
// Loop from hell
|
||||
outer:
|
||||
for (var R1 : typeVariables) {
|
||||
if (typeVariablesOfClass.contains(R1)) continue;
|
||||
for (var generic : all)
|
||||
if (generic instanceof PairLT ptph) {
|
||||
for (var pair : simplifiedConstraints) {
|
||||
if (!(pair.left.equals(R1) && pair.right.equals(ptph.left)))
|
||||
continue;
|
||||
|
||||
for (var R2 : typeVariables) {
|
||||
for (var pair2 : simplifiedConstraints) {
|
||||
|
||||
if (!(pair2.right.equals(R2) && pair2.left.equals(ptph.right)))
|
||||
continue;
|
||||
if (R1.equals(R2)) continue;
|
||||
if (!T1s.contains(R1) || !T2s.contains(R2)) continue;
|
||||
|
||||
var newPair = new PairLT(R1, R2);
|
||||
System.out.println("New pair: " + newPair);
|
||||
newPairs.add(newPair);
|
||||
|
||||
if (!containsRelation(result, newPair))
|
||||
addToPairs(result, newPair);
|
||||
continue outer;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
simplifiedConstraints.addAll(newPairs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(LambdaExpression lambdaExpression) {
|
||||
superType = new Void(new NullToken());
|
||||
lambdaExpression.methodBody.accept(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(Assign assign) {
|
||||
superType = assign.rightSide.getType();
|
||||
assign.rightSide.accept(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(BinaryExpr binary) {
|
||||
superType = new Void(new NullToken());
|
||||
binary.lexpr.accept(this);
|
||||
superType = new Void(new NullToken());
|
||||
binary.rexpr.accept(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(Block block) {
|
||||
for (var expr : block.statements) {
|
||||
superType = new de.dhbwstuttgart.syntaxtree.type.Void(new NullToken());
|
||||
expr.accept(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(IfStmt ifStmt) {
|
||||
superType = new Void(new NullToken());
|
||||
ifStmt.expr.accept(this);
|
||||
superType = new Void(new NullToken());
|
||||
ifStmt.then_block.accept(this);
|
||||
superType = new Void(new NullToken());
|
||||
if (ifStmt.else_block != null)
|
||||
ifStmt.else_block.accept(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(Return aReturn) {
|
||||
superType = aReturn.getType();
|
||||
aReturn.retexpr.accept(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WhileStmt whileStmt) {
|
||||
superType = new Void(new NullToken());
|
||||
whileStmt.expr.accept(this);
|
||||
superType = new Void(new NullToken());
|
||||
whileStmt.loopBlock.accept(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(ArgumentList arglist) {
|
||||
for (int i = 0; i < arglist.getArguments().size(); i++) {
|
||||
superType = arglist.getArguments().get(i).getType();
|
||||
arglist.getArguments().get(i).accept(this);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
var closure = transitiveClosure(simplifiedConstraints);
|
||||
// Type variables with bounds that are also type variables of the class
|
||||
for (var typeVariable : new HashSet<>(typeVariables)) {
|
||||
if (typeVariablesOfClass.contains(typeVariable)) continue;
|
||||
|
||||
var pairs = new HashSet<PairLT>();
|
||||
for (var pair : closure) {
|
||||
if (!(pair instanceof PairLT ptph)) continue;
|
||||
if (ptph.left.equals(typeVariable) && typeVariablesOfClass.contains(ptph.right)) {
|
||||
pairs.add(new PairLT(ptph.left, ptph.right));
|
||||
}
|
||||
}
|
||||
|
||||
// Find the closest pair with the minimum amount of steps
|
||||
PairLT minimalPair = null;
|
||||
var minSteps = Integer.MAX_VALUE;
|
||||
for (var pair : pairs) {
|
||||
var left = pair.left;
|
||||
var visited = new HashSet<TPH>();
|
||||
var steps = 0;
|
||||
while (!left.equals(pair.right)) {
|
||||
visited.add(left);
|
||||
var found = false;
|
||||
for (var pair2 : simplifiedConstraints) {
|
||||
if (left.equals(pair2.left) && !visited.contains(pair2.right)) {
|
||||
left = pair2.right;
|
||||
steps += 1;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) break;
|
||||
}
|
||||
if (steps < minSteps) {
|
||||
minSteps = steps;
|
||||
minimalPair = pair;
|
||||
}
|
||||
}
|
||||
|
||||
if (minimalPair != null)
|
||||
addToPairs(result, minimalPair);
|
||||
}
|
||||
|
||||
// All unbounded type variables (bounds not in method)
|
||||
outer:
|
||||
for (var typeVariable : typeVariables) {
|
||||
if (classHasGeneric(userDefinedGenericsOfClass, typeVariablesOfClass, typeVariable))
|
||||
continue;
|
||||
for (var pair : result) {
|
||||
if (pair.left.equals(typeVariable))
|
||||
continue outer;
|
||||
}
|
||||
addToPairs(result, new PairEQ(typeVariable, ASTToTargetAST.OBJECT));
|
||||
}
|
||||
|
||||
// All unbounded bounds
|
||||
outer:
|
||||
for (var pair : simplifiedConstraints) {
|
||||
for (var pair2 : simplifiedConstraints) {
|
||||
if (pair.right.equals(pair2.left))
|
||||
continue outer;
|
||||
}
|
||||
if (!classHasGeneric(userDefinedGenericsOfClass, typeVariablesOfClass, pair.right) && typeVariables.contains(pair.right)) {
|
||||
addToPairs(result, new PairEQ(pair.right, ASTToTargetAST.OBJECT));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean classHasGeneric(Set<GenericTypeVar> userDefinedGenericsOfClass, Set<TPH> typeVariablesOfClass, TPH typeVariable) {
|
||||
return typeVariablesOfClass.contains(typeVariable) || userDefinedGenericsOfClass.stream().anyMatch(g -> g.getName().equals(typeVariable.resolve().getName()));
|
||||
}
|
||||
|
||||
private void methodFindTypeVariables(
|
||||
Method method,
|
||||
Set<TPH> typeVariables
|
||||
) {
|
||||
|
||||
if (!(method instanceof Constructor))
|
||||
typeVariables.addAll(findTypeVariables(method.getReturnType()));
|
||||
for (var arg : method.getParameterList().getFormalparalist()) {
|
||||
typeVariables.addAll(findTypeVariables(arg.getType()));
|
||||
}
|
||||
|
||||
if (method.block != null)
|
||||
method.block.accept(new TracingStatementVisitor() {
|
||||
@Override
|
||||
public void visit(LocalVarDecl localVarDecl) {
|
||||
typeVariables.addAll(findTypeVariables(localVarDecl.getType()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(MethodCall methodCall) {
|
||||
super.visit(methodCall);
|
||||
typeVariables.addAll(findTypeVariables(methodCall.getType()));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
abstract void generics(ClassOrInterface owner, Method method, Set<Pair> result, Set<TPH> javaTypeVariablesOfClass);
|
||||
|
||||
Set<Pair> family(ClassOrInterface owner, Method method) {
|
||||
Set<Pair> result = new HashSet<>();
|
||||
if (familyOfMethods.containsKey(method))
|
||||
return familyOfMethods.get(method);
|
||||
|
||||
familyOfMethods.put(method, result);
|
||||
|
||||
var classGenerics = generics(owner);
|
||||
HashSet<TPH> typeVariablesOfClass = new HashSet<>();
|
||||
|
||||
for (var pair : classGenerics) {
|
||||
typeVariablesOfClass.add(pair.left);
|
||||
}
|
||||
|
||||
HashSet<TPH> javaTypeVariables = new HashSet<>();
|
||||
|
||||
methodFindTypeVariables(method, javaTypeVariables);
|
||||
methodFindConstraints(owner, method, javaTypeVariables, typeVariablesOfClass, result);
|
||||
eliminateTransitives(result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Set<Pair> generics(ClassOrInterface owner, Method method) {
|
||||
if (computedGenericsOfMethods.containsKey(method)) {
|
||||
var cached = computedGenericsOfMethods.get(method);
|
||||
System.out.println("Cached " + method.getName() + ": " + cached);
|
||||
return cached;
|
||||
}
|
||||
|
||||
var result = new HashSet<Pair>();
|
||||
computedGenericsOfMethods.put(method, result);
|
||||
|
||||
var classGenerics = generics(owner);
|
||||
HashSet<TPH> typeVariablesOfClass = new HashSet<>();
|
||||
for (var pair : classGenerics) {
|
||||
typeVariablesOfClass.add(pair.left);
|
||||
}
|
||||
|
||||
result.addAll(family(owner, method));
|
||||
|
||||
var referenced = new HashSet<TPH>();
|
||||
|
||||
var usedTphs = new HashSet<TPH>();
|
||||
// For eliminating inner type variables we need to figure out which ones are actually used
|
||||
for (var param : method.getParameterList().getFormalparalist()) {
|
||||
usedTphs.addAll(findTypeVariables(param.getType()));
|
||||
}
|
||||
usedTphs.addAll(findTypeVariables(method.getReturnType()));
|
||||
referenced.addAll(usedTphs);
|
||||
referenced.addAll(typeVariablesOfClass);
|
||||
|
||||
generics(owner, method, result, referenced);
|
||||
usedTPHsOfMethods.put(method, usedTphs);
|
||||
|
||||
normalize(result, classGenerics, usedTphs);
|
||||
|
||||
System.out.println(this.getClass().getSimpleName() + " " + method.name + ": " + result);
|
||||
return result;
|
||||
}
|
||||
|
||||
private void eliminateChain(Set<Pair> result, List<TPH> chain) {
|
||||
for (var pair : new HashSet<>(result)) {
|
||||
if (pair instanceof PairLT ptph && chain.get(chain.size() - 1).equals(ptph.left)) {
|
||||
if (chain.contains(ptph.right)) return;
|
||||
var copy = new ArrayList<>(chain);
|
||||
copy.add(ptph.right);
|
||||
if (copy.size() > 2)
|
||||
result.remove(new PairLT(chain.get(0), ptph.right));
|
||||
eliminateChain(result, copy);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void eliminateTransitives(Set<Pair> result) {
|
||||
for (var pair : new HashSet<>(result))
|
||||
if (pair instanceof PairLT ptph) {
|
||||
var first = ptph.left;
|
||||
var chain = new ArrayList<TPH>();
|
||||
chain.add(ptph.left);
|
||||
chain.add(ptph.right);
|
||||
eliminateChain(result, chain);
|
||||
}
|
||||
}
|
||||
|
||||
void findAllBounds(RefTypeOrTPHOrWildcardOrGeneric type, Set<Pair> generics) {
|
||||
if (type instanceof TypePlaceholder tph) {
|
||||
var nTph = new TPH(tph);
|
||||
var concreteType = concreteTypes.get(nTph);
|
||||
if (concreteType != null) {
|
||||
findAllBounds(concreteType, generics);
|
||||
return;
|
||||
}
|
||||
|
||||
var found = false;
|
||||
for (var rsp : simplifiedConstraints) {
|
||||
if (rsp.left.equals(nTph)) {
|
||||
var pair = new PairLT(new TPH(tph), rsp.right);
|
||||
if (!generics.contains(pair)) {
|
||||
addToPairs(generics, pair);
|
||||
findAllBounds(rsp.right.resolve(), generics);
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
addToPairs(generics, new PairEQ(nTph, ASTToTargetAST.OBJECT));
|
||||
} else if (type instanceof RefType refType) {
|
||||
refType.getParaList().forEach(t -> findAllBounds(t, generics));
|
||||
}
|
||||
}
|
||||
|
||||
abstract void generics(ClassOrInterface classOrInterface, Set<Pair> result, Set<TPH> referenced);
|
||||
|
||||
Set<Pair> generics(ClassOrInterface classOrInterface) {
|
||||
if (computedGenericsOfClasses.containsKey(classOrInterface))
|
||||
return computedGenericsOfClasses.get(classOrInterface);
|
||||
|
||||
Set<Pair> javaResult = new HashSet<>();
|
||||
computedGenericsOfClasses.put(classOrInterface, javaResult);
|
||||
|
||||
for (var field : classOrInterface.getFieldDecl()) {
|
||||
findAllBounds(field.getType(), javaResult);
|
||||
}
|
||||
|
||||
var referenced = new HashSet<TPH>();
|
||||
eliminateTransitives(javaResult);
|
||||
generics(classOrInterface, javaResult, referenced);
|
||||
|
||||
var referencedByClass = new HashSet<TPH>();
|
||||
for (var field : classOrInterface.getFieldDecl()) {
|
||||
findTphs(field.getType(), referencedByClass);
|
||||
}
|
||||
|
||||
normalize(javaResult, null, referencedByClass);
|
||||
|
||||
System.out.println(this.getClass().getSimpleName() + " Class " + classOrInterface.getClassName().getClassName() + ": " + javaResult);
|
||||
return javaResult;
|
||||
}
|
||||
|
||||
void normalize(Set<Pair> result, Set<Pair> classGenerics, Set<TPH> usedTphs) {
|
||||
outer:
|
||||
for (var tph : usedTphs) {
|
||||
for (var p1 : new HashSet<>(result)) {
|
||||
if (p1 instanceof PairLT ptph && ptph.left.equals(ptph.right))
|
||||
result.remove(p1); // TODO This is a bit strange
|
||||
if (p1.left.equals(tph)) continue outer;
|
||||
}
|
||||
|
||||
if (classGenerics == null || classGenerics.stream().noneMatch((pair) -> pair.left.equals(tph)))
|
||||
addToPairs(result, new PairEQ(tph, ASTToTargetAST.OBJECT));
|
||||
}
|
||||
}
|
||||
|
||||
private record ToAdd(TypePlaceholder left, TypePlaceholder right) {}
|
||||
|
||||
void equalizeTypeVariables(Set<Pair> input, Set<TPH> referenced) {
|
||||
|
||||
var elementsToAddToEquality = new ArrayList<ToAdd>();
|
||||
|
||||
for (var pair : new HashSet<>(input)) {
|
||||
if (pair instanceof PairLT ptph && referenced.contains(ptph.left)) {
|
||||
var chain = new ArrayList<TPH>();
|
||||
chain.add(ptph.left);
|
||||
chain.add(ptph.right);
|
||||
|
||||
outer:
|
||||
while (true) {
|
||||
var added = false;
|
||||
for (var pair2 : input) {
|
||||
if (pair2 instanceof PairLT ptph2 && ptph2.left.equals(chain.get(chain.size() - 1))) {
|
||||
if (chain.contains(ptph2.right)) break outer;
|
||||
chain.add(ptph2.right);
|
||||
added = true;
|
||||
}
|
||||
}
|
||||
if (!added) break;
|
||||
}
|
||||
|
||||
System.out.println(chain + " " + chain.stream().map(e -> e.resolve().getVariance()).toList());
|
||||
var variance = chain.get(0).resolve().getVariance();
|
||||
if (variance != 1) continue;
|
||||
var index = 0;
|
||||
for (var tph : chain) {
|
||||
if (variance == 1 && tph.resolve().getVariance() == -1) {
|
||||
variance = -1;
|
||||
}
|
||||
if (variance == -1 && tph.resolve().getVariance() == 1 && referenced.contains(tph)) {
|
||||
break;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
if (variance == 1) continue;
|
||||
|
||||
|
||||
var start = chain.get(0);
|
||||
var prev = start;
|
||||
for (var i = 1; i < index; i++) {
|
||||
var cur = chain.get(i);
|
||||
if (!referenced.contains(cur)) continue;
|
||||
elementsToAddToEquality.add(new ToAdd(cur.resolve(), start.resolve()));
|
||||
//addToEquality(cur.resolve(), start.resolve(), referenced);
|
||||
TPH finalPrev = prev;
|
||||
input.removeIf(p -> p.equals(new PairLT(finalPrev, cur)));
|
||||
for (var pair2 : new HashSet<>(input)) {
|
||||
// TODO Maybe this would be unnecessary if we were to add the = constraints later on
|
||||
if (pair2 instanceof PairEQ peq && pair.left.equals(cur)) {
|
||||
input.remove(pair2);
|
||||
input.add(new PairEQ(start, peq.right));
|
||||
}
|
||||
}
|
||||
prev = chain.get(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (var pair : elementsToAddToEquality) {
|
||||
System.out.println(pair);
|
||||
addToEquality(pair.left, pair.right, referenced);
|
||||
}
|
||||
}
|
||||
|
||||
void findTphs(RefTypeOrTPHOrWildcardOrGeneric type, Set<TPH> tphs) {
|
||||
if (type instanceof RefType refType) {
|
||||
refType.getParaList().forEach(t -> findTphs(t, tphs));
|
||||
} else if (type instanceof TypePlaceholder tph) {
|
||||
tph = equality.getOrDefault(tph, tph);
|
||||
var concreteType = concreteTypes.get(new TPH(tph));
|
||||
if (concreteType != null) {
|
||||
findTphs(concreteType, tphs);
|
||||
return;
|
||||
}
|
||||
tphs.add(new TPH(tph));
|
||||
}
|
||||
}
|
||||
|
||||
void eliminateInnerTypeVariablesOfClass(ClassOrInterface classOrInterface, Set<Pair> input, Set<TPH> referenced) {
|
||||
for (var field : classOrInterface.getFieldDecl()) {
|
||||
findTphs(field.getType(), referenced);
|
||||
}
|
||||
doIterationForMethods(classOrInterface);
|
||||
for (var method : classOrInterface.getMethods()) {
|
||||
var usedTPHs = usedTPHsOfMethods.get(method);
|
||||
if (usedTPHs != null)
|
||||
referenced.addAll(usedTPHs);
|
||||
}
|
||||
eliminateInnerTypeVariables(referenced, input);
|
||||
}
|
||||
|
||||
void doIterationForMethods(ClassOrInterface classOrInterface) {
|
||||
familyOfMethods.clear();
|
||||
|
||||
var oldFamily = new HashMap<Method, Set<Pair>>();
|
||||
do {
|
||||
oldFamily.clear();
|
||||
oldFamily.putAll(familyOfMethods);
|
||||
familyOfMethods.clear();
|
||||
Stream.concat(classOrInterface.getMethods().stream(), classOrInterface.getConstructors().stream()).forEach(method -> {
|
||||
family(classOrInterface, method);
|
||||
});
|
||||
} while(!oldFamily.equals(familyOfMethods));
|
||||
|
||||
Stream.concat(classOrInterface.getMethods().stream(), classOrInterface.getConstructors().stream()).forEach(method -> {
|
||||
generics(classOrInterface, method);
|
||||
});
|
||||
}
|
||||
|
||||
private void findChain(Set<TPH> referenced, Set<Pair> input, Set<Pair> output, TPH start, TPH end, Set<TPH> chain) {
|
||||
if (referenced.contains(end)) {
|
||||
var pair = new PairLT(start, end);
|
||||
output.add(pair);
|
||||
return;
|
||||
}
|
||||
var foundNext = false;
|
||||
for (var pair : input) {
|
||||
if (pair instanceof PairLT ptph && ptph.left.equals(end)) {
|
||||
if (chain.contains(ptph.right)) return;
|
||||
chain = new HashSet<>(chain);
|
||||
chain.add(ptph.right);
|
||||
findChain(referenced, input, output, start, ptph.right, chain);
|
||||
foundNext = true;
|
||||
}
|
||||
}
|
||||
if (!foundNext) {
|
||||
output.add(new PairEQ(start, ASTToTargetAST.OBJECT));
|
||||
}
|
||||
}
|
||||
|
||||
void eliminateInnerTypeVariables(Set<TPH> referenced, Set<Pair> input) {
|
||||
var output = new HashSet<Pair>();
|
||||
for (var tph : referenced) {
|
||||
for (var pair : input) {
|
||||
if (pair instanceof PairLT pthp && pthp.left.equals(tph)) {
|
||||
var chain = new HashSet<TPH>();
|
||||
chain.add(tph);
|
||||
findChain(referenced, input, output, tph, pthp.right, chain);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (var pair : input) {
|
||||
if (pair instanceof PairEQ rtph) {
|
||||
if (referenced.contains(rtph.left))
|
||||
output.add(rtph);
|
||||
}
|
||||
}
|
||||
|
||||
input.clear();
|
||||
input.addAll(output);
|
||||
}
|
||||
|
||||
void eliminateCycles(Set<Pair> input, Set<TPH> referenced) {
|
||||
var cycles = CycleFinder.findCycles(input);
|
||||
for (var cycle : cycles) {
|
||||
var newTph = TypePlaceholder.fresh(new NullToken());
|
||||
var variance = cycle.get(0).resolve().getVariance();
|
||||
for (var tph : cycle) {
|
||||
if (tph.resolve().getVariance() != variance) {
|
||||
variance = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
newTph.setVariance(variance);
|
||||
|
||||
referenced.add(new TPH(newTph));
|
||||
addToPairs(input, new PairEQ(new TPH(newTph), ASTToTargetAST.OBJECT));
|
||||
cycle.add(cycle.get(0)); // Make it a complete cycle
|
||||
for (var i = 0; i < cycle.size() - 1; i++) {
|
||||
var left = cycle.get(i);
|
||||
var right = cycle.get(i + 1);
|
||||
var pair = new PairLT(left, right);
|
||||
input.remove(pair);
|
||||
addToEquality(left.resolve(), newTph, referenced);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Set<TPH> findConnectionToReturnType(Set<TPH> returnTypes, Set<Pair> input, Set<TPH> visited, TPH tph) {
|
||||
if (returnTypes.contains(tph)) {
|
||||
var res = new HashSet<TPH>();
|
||||
res.add(tph);
|
||||
return res;
|
||||
} else {
|
||||
for (var pair : input) if (pair instanceof PairLT ptph) {
|
||||
if (ptph.left.equals(tph) && !visited.contains(ptph.right)) {
|
||||
visited.add(ptph.right);
|
||||
var result = findConnectionToReturnType(returnTypes, input, visited, ptph.right);
|
||||
if (result.size() > 0) {
|
||||
result.add(ptph.right);
|
||||
return result;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
return new HashSet<>();
|
||||
}
|
||||
|
||||
void eliminateInfimaConnectedToReturnType(Method method, Set<Pair> input, Set<TPH> referenced) {
|
||||
var foundInfima = false;
|
||||
do {
|
||||
foundInfima = false;
|
||||
for (var constraint : new HashSet<>(input)) {
|
||||
var left = constraint.left;
|
||||
Set<PairLT> infima = new HashSet<>();
|
||||
for (var pair : input) {
|
||||
if (pair instanceof PairLT stph) {
|
||||
if (pair.left.equals(constraint.left))
|
||||
infima.add(stph);
|
||||
}
|
||||
}
|
||||
if (infima.size() > 1) {
|
||||
System.out.println(infima);
|
||||
for (var pair : infima) {
|
||||
var returnTypes = findTypeVariables(method.getReturnType());
|
||||
var chain = findConnectionToReturnType(returnTypes, input, new HashSet<>(), pair.left);
|
||||
System.out.println("Find: " + pair.left + " " + chain);
|
||||
chain.remove(pair.left);
|
||||
if (chain.size() > 0) {
|
||||
for (var tph : chain)
|
||||
addToEquality(pair.left.resolve(), tph.resolve(), referenced);
|
||||
foundInfima = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (foundInfima);
|
||||
input.removeIf((i) -> (i instanceof PairLT lt) && lt.left.equals(lt.right));
|
||||
}
|
||||
|
||||
void eliminateInfima(Set<Pair> input, Set<TPH> referenced) {
|
||||
var foundInfima = false;
|
||||
do {
|
||||
foundInfima = false;
|
||||
for (var constraint : new HashSet<>(input)) {
|
||||
var left = constraint.left;
|
||||
Set<PairLT> infima = new HashSet<>();
|
||||
for (var pair : input) {
|
||||
if (pair instanceof PairLT stph) {
|
||||
if (pair.left.equals(constraint.left))
|
||||
infima.add(stph);
|
||||
}
|
||||
}
|
||||
if (infima.size() > 1) {
|
||||
foundInfima = true;
|
||||
var newTph = TypePlaceholder.fresh(new NullToken());
|
||||
var variance = infima.stream().findFirst().get().right.resolve().getVariance();
|
||||
for (var pair : infima) {
|
||||
if (pair.right.resolve().getVariance() != variance) {
|
||||
variance = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
newTph.setVariance(variance);
|
||||
System.out.println(infima + " " + infima.stream().map(i -> i.right.resolve().getVariance()).toList());
|
||||
System.out.println("Infima new TPH " + newTph + " variance " + variance);
|
||||
|
||||
//referenced.add(newTph);
|
||||
addToPairs(input, new PairLT(left, new TPH(newTph)));
|
||||
input.removeAll(infima);
|
||||
for (var infimum : infima) {
|
||||
addToEquality(infimum.right.resolve(), newTph, referenced);
|
||||
new HashSet<>(input).forEach(pair -> {
|
||||
if (pair.left.equals(infimum.right)) {
|
||||
input.remove(pair);
|
||||
if (pair instanceof PairLT stph) {
|
||||
if (!newTph.equals(stph.right.resolve()))
|
||||
addToPairs(input, new PairLT(new TPH(newTph), stph.right));
|
||||
} else if (pair instanceof PairEQ rtph) {
|
||||
addToPairs(input, new PairEQ(new TPH(newTph), rtph.right));
|
||||
}
|
||||
} else if (pair instanceof PairLT stph && stph.right.equals(infimum.right)) {
|
||||
input.remove(pair);
|
||||
if (!newTph.equals(stph.left.resolve()))
|
||||
addToPairs(input, new PairLT(stph.left, new TPH(newTph)));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (foundInfima);
|
||||
}
|
||||
|
||||
RefTypeOrTPHOrWildcardOrGeneric getType(RefTypeOrTPHOrWildcardOrGeneric type) {
|
||||
if (type instanceof TypePlaceholder tph) {
|
||||
if (equality.containsKey(tph)) {
|
||||
return getType(equality.get(tph));
|
||||
}
|
||||
return concreteTypes.getOrDefault(new TPH(tph), tph);
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
TargetType getTargetType(RefTypeOrTPHOrWildcardOrGeneric in) {
|
||||
if (in instanceof TypePlaceholder tph) {
|
||||
if (equality.containsKey(tph)) {
|
||||
return getTargetType(equality.get(tph));
|
||||
}
|
||||
var type = concreteTypes.get(new TPH(tph));
|
||||
if (type == null) return new TargetGenericType(tph.getName());
|
||||
return astToTargetAST.convert(type, this);
|
||||
}
|
||||
return astToTargetAST.convert(in, this);
|
||||
}
|
||||
}
|
@ -1,76 +0,0 @@
|
||||
package de.dhbwstuttgart.target.generate;
|
||||
|
||||
import de.dhbwstuttgart.syntaxtree.ClassOrInterface;
|
||||
import de.dhbwstuttgart.syntaxtree.Method;
|
||||
import de.dhbwstuttgart.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric;
|
||||
import de.dhbwstuttgart.syntaxtree.type.TypePlaceholder;
|
||||
import de.dhbwstuttgart.target.tree.type.TargetType;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class GenericsResult {
|
||||
private final GenerateGenerics generics;
|
||||
|
||||
GenericsResult(GenerateGenerics generics) {
|
||||
this.generics = generics;
|
||||
}
|
||||
|
||||
public GenericsResultSet get(ClassOrInterface clazz) {
|
||||
var generics = this.generics.computedGenericsOfClasses.get(clazz);
|
||||
return new GenericsResultSet(generics, this.generics.equality);
|
||||
}
|
||||
|
||||
// TODO Compute generics if not present?
|
||||
public GenericsResultSet get(Method method) {
|
||||
var generics = this.generics.computedGenericsOfMethods.get(method);
|
||||
return new GenericsResultSet(generics, this.generics.equality);
|
||||
}
|
||||
|
||||
public BoundsList getBounds(RefTypeOrTPHOrWildcardOrGeneric type, ClassOrInterface clazz) {
|
||||
return getBounds(type, clazz, null);
|
||||
}
|
||||
|
||||
public BoundsList getBounds(RefTypeOrTPHOrWildcardOrGeneric type, ClassOrInterface clazz, Method method) {
|
||||
var resolvedType = resolve(type);
|
||||
type = resolvedType;
|
||||
if (type instanceof TypePlaceholder) {
|
||||
var methodGenerics = get(method);
|
||||
var classGenerics = get(clazz);
|
||||
List<Bound> result = new ArrayList<>();
|
||||
|
||||
Optional<Bound> bound = Optional.empty();
|
||||
do {
|
||||
bound = Optional.empty();
|
||||
for (var pair : methodGenerics) {
|
||||
if (pair.left.resolve().equals(type)) {
|
||||
type = pair.resolveRight();
|
||||
bound = Optional.of(new Bound(true, type));
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (bound.isEmpty()) {
|
||||
for (var pair : classGenerics) {
|
||||
if (pair.left.resolve().equals(type)) {
|
||||
type = pair.resolveRight();
|
||||
bound = Optional.of(new Bound(false, type));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
bound.ifPresent(result::add);
|
||||
} while (bound.isPresent());
|
||||
return new BoundsList(resolvedType, result);
|
||||
}
|
||||
return new BoundsList(resolvedType, List.of());
|
||||
}
|
||||
|
||||
public RefTypeOrTPHOrWildcardOrGeneric resolve(RefTypeOrTPHOrWildcardOrGeneric type) {
|
||||
if (type instanceof TypePlaceholder tph)
|
||||
return this.generics.getType(tph);
|
||||
return type;
|
||||
}
|
||||
|
||||
public TargetType resolveTarget(RefTypeOrTPHOrWildcardOrGeneric type) {
|
||||
return this.generics.getTargetType(type);
|
||||
}
|
||||
}
|
@ -1,43 +0,0 @@
|
||||
package de.dhbwstuttgart.target.generate;
|
||||
|
||||
import de.dhbwstuttgart.syntaxtree.type.TypePlaceholder;
|
||||
import de.dhbwstuttgart.typeinference.result.PairTPHequalRefTypeOrWildcardType;
|
||||
import de.dhbwstuttgart.typeinference.result.PairTPHsmallerTPH;
|
||||
import de.dhbwstuttgart.typeinference.result.ResultPair;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class GenericsResultSet extends AbstractSet<GenerateGenerics.Pair> {
|
||||
|
||||
final Set<GenerateGenerics.Pair> backing;
|
||||
final Map<TypePlaceholder, TypePlaceholder> equality;
|
||||
|
||||
public GenericsResultSet(Set<GenerateGenerics.Pair> backing, Map<TypePlaceholder, TypePlaceholder> equality) {
|
||||
this.backing = backing == null ? new HashSet<>() : new HashSet<>(backing);
|
||||
this.equality = equality;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<GenerateGenerics.Pair> iterator() {
|
||||
return backing.iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return backing.size();
|
||||
}
|
||||
|
||||
public Optional<ResultPair<?, ?>> getResultPairFor(TypePlaceholder tph) {
|
||||
var tph2 = equality.getOrDefault(tph, tph);
|
||||
return this.stream().filter(pair -> {
|
||||
return pair.left.resolve().equals(tph2);
|
||||
}).findFirst().map(pair -> {
|
||||
ResultPair<?, ?> res = null;
|
||||
if (pair instanceof GenerateGenerics.PairLT lt)
|
||||
res = new PairTPHsmallerTPH(lt.left.resolve(), lt.right.resolve());
|
||||
else if (pair instanceof GenerateGenerics.PairEQ eq)
|
||||
res = new PairTPHequalRefTypeOrWildcardType(eq.left.resolve(), eq.right);
|
||||
return res;
|
||||
});
|
||||
}
|
||||
}
|
@ -1,30 +0,0 @@
|
||||
package de.dhbwstuttgart.target.generate;
|
||||
|
||||
import de.dhbwstuttgart.syntaxtree.ClassOrInterface;
|
||||
import de.dhbwstuttgart.syntaxtree.Method;
|
||||
import de.dhbwstuttgart.typeinference.result.ResultSet;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
final class JavaGenerics extends GenerateGenerics {
|
||||
JavaGenerics(ASTToTargetAST astToTargetAST, ResultSet constraints) {
|
||||
super(astToTargetAST, constraints);
|
||||
}
|
||||
|
||||
@Override
|
||||
void generics(ClassOrInterface owner, Method method, Set<Pair> result, Set<TPH> referenced) {
|
||||
eliminateCycles(result, referenced);
|
||||
eliminateInfimaConnectedToReturnType(method, result, referenced);
|
||||
eliminateInfima(result, referenced);
|
||||
equalizeTypeVariables(result, referenced);
|
||||
eliminateInnerTypeVariables(referenced, result);
|
||||
}
|
||||
|
||||
@Override
|
||||
void generics(ClassOrInterface classOrInterface, Set<Pair> result, Set<TPH> referenced) {
|
||||
eliminateCycles(result, referenced);
|
||||
eliminateInfima(result, referenced);
|
||||
eliminateInnerTypeVariablesOfClass(classOrInterface, result, referenced);
|
||||
equalizeTypeVariables(result, referenced);
|
||||
}
|
||||
}
|
@ -1,503 +0,0 @@
|
||||
package de.dhbwstuttgart.target.generate;
|
||||
|
||||
import de.dhbwstuttgart.exceptions.DebugException;
|
||||
import de.dhbwstuttgart.exceptions.NotImplementedException;
|
||||
import de.dhbwstuttgart.parser.NullToken;
|
||||
import de.dhbwstuttgart.parser.SyntaxTreeGenerator.AssignToLocal;
|
||||
import de.dhbwstuttgart.parser.scope.JavaClassName;
|
||||
import de.dhbwstuttgart.syntaxtree.*;
|
||||
import de.dhbwstuttgart.syntaxtree.factory.PrimitiveMethodsGenerator;
|
||||
import de.dhbwstuttgart.syntaxtree.statement.*;
|
||||
import de.dhbwstuttgart.syntaxtree.type.*;
|
||||
import de.dhbwstuttgart.target.tree.MethodParameter;
|
||||
import de.dhbwstuttgart.target.tree.TargetGeneric;
|
||||
import de.dhbwstuttgart.target.tree.TargetMethod;
|
||||
import de.dhbwstuttgart.target.tree.expression.*;
|
||||
import de.dhbwstuttgart.target.tree.type.*;
|
||||
|
||||
import javax.swing.text.html.Option;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.*;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
public class StatementToTargetExpression implements ASTVisitor {
|
||||
|
||||
public StatementToTargetExpression(ASTToTargetAST converter) {
|
||||
this.converter = converter;
|
||||
}
|
||||
|
||||
public TargetExpression result;
|
||||
private final ASTToTargetAST converter;
|
||||
|
||||
@Override
|
||||
public void visit(ArgumentList argumentList) {
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(LambdaExpression lambdaExpression) {
|
||||
var parameters = StreamSupport.stream(lambdaExpression.params.spliterator(), false)
|
||||
.map(p -> (FormalParameter) p)
|
||||
.map(p -> new MethodParameter(new TargetTypePattern(converter.convert(p.getType()), p.getName())))
|
||||
.toList();
|
||||
|
||||
List<MethodParameter> captures = new ArrayList<>();
|
||||
lambdaExpression.methodBody.accept(new TracingStatementVisitor() {
|
||||
// TODO The same mechanism is implemented in Codegen, maybe use it from there?
|
||||
final Stack<Set<String>> localVariables = new Stack<>();
|
||||
{
|
||||
localVariables.push(new HashSet<>());
|
||||
}
|
||||
|
||||
boolean hasLocalVar(String name) {
|
||||
for (var localVariables : this.localVariables) {
|
||||
if (localVariables.contains(name))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(Block block) {
|
||||
localVariables.push(new HashSet<>());
|
||||
super.visit(block);
|
||||
localVariables.pop();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(LocalVar localVar) {
|
||||
super.visit(localVar);
|
||||
var capture = new MethodParameter(new TargetTypePattern(converter.convert(localVar.getType()), localVar.name));
|
||||
if (!hasLocalVar(localVar.name) && !parameters.contains(capture) && !captures.contains(capture))
|
||||
captures.add(capture);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(LocalVarDecl varDecl) {
|
||||
var localVariables = this.localVariables.peek();
|
||||
localVariables.add(varDecl.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(LambdaExpression lambda) {
|
||||
} // Don't look at lambda expressions
|
||||
});
|
||||
|
||||
TargetMethod.Signature signature = new TargetMethod.Signature(Set.of(), parameters, converter.convert(lambdaExpression.getReturnType()));;
|
||||
var tpe = converter.convert(lambdaExpression.getType());
|
||||
result = new TargetLambdaExpression(tpe, captures, signature, converter.convert(lambdaExpression.methodBody));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(Assign assign) {
|
||||
TargetExpression left;
|
||||
if (assign.lefSide instanceof AssignToLocal) {
|
||||
left = converter.convert(((AssignToLocal) assign.lefSide).localVar);
|
||||
} else {
|
||||
left = converter.convert(((AssignToField) assign.lefSide).field);
|
||||
}
|
||||
|
||||
result = new TargetAssign(converter.convert(assign.getType()), left, converter.convert(assign.rightSide));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(BinaryExpr binary) {
|
||||
result = switch (binary.operation) {
|
||||
case ADD -> new TargetBinaryOp.Add(converter.convert(binary.getType()), converter.convert(binary.lexpr), converter.convert(binary.rexpr));
|
||||
case SUB -> new TargetBinaryOp.Sub(converter.convert(binary.getType()), converter.convert(binary.lexpr), converter.convert(binary.rexpr));
|
||||
case MUL -> new TargetBinaryOp.Mul(converter.convert(binary.getType()), converter.convert(binary.lexpr), converter.convert(binary.rexpr));
|
||||
case MOD -> new TargetBinaryOp.Rem(converter.convert(binary.getType()), converter.convert(binary.lexpr), converter.convert(binary.rexpr));
|
||||
case AND -> new TargetBinaryOp.BAnd(converter.convert(binary.getType()), converter.convert(binary.lexpr), converter.convert(binary.rexpr));
|
||||
case OR -> new TargetBinaryOp.BOr(converter.convert(binary.getType()), converter.convert(binary.lexpr), converter.convert(binary.rexpr));
|
||||
case XOR -> new TargetBinaryOp.XOr(converter.convert(binary.getType()), converter.convert(binary.lexpr), converter.convert(binary.rexpr));
|
||||
case DIV -> new TargetBinaryOp.Div(converter.convert(binary.getType()), converter.convert(binary.lexpr), converter.convert(binary.rexpr));
|
||||
case LESSTHAN -> new TargetBinaryOp.Less(converter.convert(binary.getType()), converter.convert(binary.lexpr), converter.convert(binary.rexpr));
|
||||
case BIGGERTHAN -> new TargetBinaryOp.Greater(converter.convert(binary.getType()), converter.convert(binary.lexpr), converter.convert(binary.rexpr));
|
||||
case LESSEQUAL -> new TargetBinaryOp.LessOrEqual(converter.convert(binary.getType()), converter.convert(binary.lexpr), converter.convert(binary.rexpr));
|
||||
case BIGGEREQUAL -> new TargetBinaryOp.GreaterOrEqual(converter.convert(binary.getType()), converter.convert(binary.lexpr), converter.convert(binary.rexpr));
|
||||
case EQUAL -> new TargetBinaryOp.Equal(converter.convert(binary.getType()), converter.convert(binary.lexpr), converter.convert(binary.rexpr));
|
||||
case NOTEQUAL -> new TargetBinaryOp.NotEqual(converter.convert(binary.getType()), converter.convert(binary.lexpr), converter.convert(binary.rexpr));
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(BoolExpression bool) {
|
||||
System.out.println("BoolExpression");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(Block block) {
|
||||
result = converter.convert(block);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(CastExpr castExpr) {
|
||||
result = new TargetCast(converter.convert(castExpr.getType()), converter.convert(castExpr.expr));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(EmptyStmt emptyStmt) {
|
||||
result = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(FieldVar fieldVar) {
|
||||
result = new TargetFieldVar(converter.convert(fieldVar.getType()), converter.convert(fieldVar.receiver.getType()), fieldVar.isStatic, converter.convert(fieldVar.receiver), fieldVar.fieldVarName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(ForStmt forStmt) {
|
||||
result = new TargetFor(
|
||||
forStmt.initializer.stream().map(converter::convert).toList(),
|
||||
forStmt.condition != null ? converter.convert(forStmt.condition) : null,
|
||||
forStmt.loopExpr.stream().map(converter::convert).toList(),
|
||||
converter.convertWrapInBlock(forStmt.block)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(ForEachStmt forEachStmt) {
|
||||
result = new TargetForEach(converter.convert(forEachStmt.statement), converter.convert(forEachStmt.expression), converter.convertWrapInBlock(forEachStmt.block));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(IfStmt ifStmt) {
|
||||
result = new TargetIf(converter.convert(ifStmt.expr), converter.convertWrapInBlock(ifStmt.then_block), ifStmt.else_block != null ? converter.convertWrapInBlock(ifStmt.else_block) : null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(InstanceOf instanceOf) {
|
||||
result = new TargetInstanceOf(converter.convert(instanceOf.getExpression()), converter.convert(instanceOf.getPattern()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(LocalVar localVar) {
|
||||
result = new TargetLocalVar(converter.convert(localVar.getType()), localVar.name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(LocalVarDecl localVarDecl) {
|
||||
// TODO No value, is this correct?
|
||||
result = new TargetVarDecl(converter.convert(localVarDecl.getType()), localVarDecl.getName(), null);
|
||||
}
|
||||
|
||||
static boolean convertsTo(TargetType from, TargetType to) {
|
||||
if (to.equals(TargetType.Object))
|
||||
return true; // TODO Consider type coercion and subtyping
|
||||
return to.equals(from);
|
||||
}
|
||||
|
||||
Optional<Method> findMethod(JavaClassName className, String name, List<TargetType> args) {
|
||||
return converter.findMethod(converter.compiler.getClass(className), name, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(MethodCall methodCall) {
|
||||
var receiverType = converter.convert(methodCall.receiver.getType());
|
||||
var isFunNType = receiverType instanceof TargetFunNType;
|
||||
|
||||
var returnType = isFunNType ? TargetType.Object : converter.convert(methodCall.signature.get(methodCall.signature.size() - 1));
|
||||
var receiverName = new JavaClassName(converter.convert(methodCall.receiver.getType()).name());
|
||||
var argList = methodCall.signature.stream().map(converter::convert).toList();
|
||||
argList = argList.subList(0, argList.size() - 1);
|
||||
|
||||
Method foundMethod = null;
|
||||
var isStatic = false;
|
||||
var isInterface = true;
|
||||
var isPrivate = false;
|
||||
var signature = methodCall.signatureArguments().stream().map(converter::convert).toList();
|
||||
|
||||
// Add used TPHs to containing method
|
||||
for (var i = 0; i < methodCall.signatureArguments().size(); i++) {
|
||||
converter.addSignaturePair(methodCall.signatureArguments().get(i), methodCall.arglist.getArguments().get(i).getType());
|
||||
}
|
||||
|
||||
var receiverClass = converter.compiler.getClass(receiverName);
|
||||
if (methodCall.receiver instanceof ExpressionReceiver expressionReceiver && expressionReceiver.expr instanceof This) {
|
||||
if (receiverClass == null) throw new DebugException("Class " + receiverName + " does not exist!");
|
||||
var thisMethod = converter.findMethod(receiverClass, methodCall.name, signature);
|
||||
ClassOrInterface finalReceiverClass = receiverClass;
|
||||
foundMethod = thisMethod.orElseGet(() -> findMethod(finalReceiverClass.getSuperClass().getName(), methodCall.name, signature).orElseThrow());
|
||||
} else if (!isFunNType) {
|
||||
receiverClass = converter.compiler.getClass(receiverName);
|
||||
if (receiverClass == null) throw new DebugException("Class " + receiverName + " does not exist!");
|
||||
foundMethod = findMethod(receiverName, methodCall.name, signature).orElseThrow();
|
||||
}
|
||||
|
||||
if (!isFunNType) {
|
||||
returnType = converter.convert(foundMethod.getReturnType());
|
||||
argList = foundMethod.getParameterList().getFormalparalist().stream().map(e -> converter.convert(e.getType())).toList();
|
||||
isStatic = Modifier.isStatic(foundMethod.modifier);
|
||||
isPrivate = Modifier.isPrivate(foundMethod.modifier);
|
||||
isInterface = receiverClass.isInterface();
|
||||
}
|
||||
|
||||
System.out.println(argList);
|
||||
result = new TargetMethodCall(converter.convert(methodCall.getType()), returnType, argList, converter.convert(methodCall.receiver), methodCall.getArgumentList().getArguments().stream().map(converter::convert).toList(), receiverType, methodCall.name, isStatic, isInterface, isPrivate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(NewClass newClass) {
|
||||
var receiverName = new JavaClassName(newClass.name);
|
||||
var ctor = converter.findConstructor(converter.compiler.getClass(receiverName), newClass.signatureArguments().stream().map(converter::convert).toList());
|
||||
var signature = ctor.orElseThrow().getParameterList().getFormalparalist().stream().map(e -> converter.convert(e.getType())).toList();
|
||||
result = new TargetNew(new TargetRefType(newClass.name), signature, newClass.getArgumentList().getArguments().stream().map(converter::convert).toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(NewArray newArray) {
|
||||
// TODO
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(Return aReturn) {
|
||||
result = new TargetReturn(converter.convert(aReturn.retexpr));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(ReturnVoid aReturn) {
|
||||
result = new TargetReturn(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(Break aBreak) {
|
||||
result = new TargetBreak();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(Continue aContinue) {
|
||||
result = new TargetContinue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(StaticClassName staticClassName) {
|
||||
result = new TargetClassName(converter.convert(staticClassName.getType()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(Super aSuper) {
|
||||
result = new TargetSuper(converter.convert(aSuper.getType()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(This aThis) {
|
||||
result = new TargetThis(converter.convert(aThis.getType()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WhileStmt whileStmt) {
|
||||
result = new TargetWhile(converter.convert(whileStmt.expr), converter.convert(whileStmt.loopBlock));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(DoStmt whileStmt) {
|
||||
result = new TargetDo(converter.convert(whileStmt.expr), converter.convert(whileStmt.loopBlock));
|
||||
}
|
||||
|
||||
// TODO These two might not be necessary
|
||||
@Override
|
||||
public void visit(AssignToField assignLeftSide) {
|
||||
result = converter.convert(assignLeftSide.field);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(AssignToLocal assignLeftSide) {
|
||||
result = converter.convert(assignLeftSide.localVar);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(SuperCall superCall) {
|
||||
var aSuper = converter.convert(superCall.receiver.getType());
|
||||
var type = converter.convert(superCall.getType());
|
||||
var receiverName = new JavaClassName(converter.convert(superCall.receiver.getType()).name());
|
||||
var clazz = converter.compiler.getClass(receiverName);
|
||||
var signature = superCall.signatureArguments().stream().map(converter::convert).toList();
|
||||
var method = converter.findConstructor(clazz, signature);
|
||||
var params = superCall.getArgumentList().getArguments().stream().map(converter::convert).toList();
|
||||
|
||||
List<TargetType> argList;
|
||||
if (method.isPresent()) {
|
||||
argList = method.get().getParameterList().getFormalparalist().stream().map(e -> converter.convert(e.getType())).toList();
|
||||
} else {
|
||||
argList = params.stream().map(TargetExpression::type).toList();
|
||||
}
|
||||
|
||||
result = new TargetMethodCall(type, null, argList, new TargetSuper(aSuper), params, aSuper, superCall.name, false, false, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(ThisCall thisCall) {
|
||||
var aThis = converter.convert(thisCall.receiver.getType());
|
||||
var type = converter.convert(thisCall.getType());
|
||||
var parameters = thisCall.arglist.getArguments().stream().map(par -> converter.convert(par.getType())).toList();
|
||||
|
||||
result = new TargetMethodCall(type, type, parameters, new TargetThis(aThis), thisCall.getArgumentList().getArguments().stream().map(converter::convert).toList(), aThis, thisCall.name, false, false, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(ExpressionReceiver expressionReceiver) {
|
||||
result = converter.convert(expressionReceiver.expr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(UnaryExpr unaryExpr) {
|
||||
result = switch (unaryExpr.operation) {
|
||||
case NOT -> new TargetUnaryOp.Not(converter.convert(unaryExpr.getType()), converter.convert(unaryExpr.expr));
|
||||
case MINUS -> new TargetUnaryOp.Negate(converter.convert(unaryExpr.getType()), converter.convert(unaryExpr.expr));
|
||||
case PREINCREMENT -> new TargetUnaryOp.PreIncrement(converter.convert(unaryExpr.getType()), converter.convert(unaryExpr.expr));
|
||||
case PREDECREMENT -> new TargetUnaryOp.PreDecrement(converter.convert(unaryExpr.getType()), converter.convert(unaryExpr.expr));
|
||||
case POSTINCREMENT -> new TargetUnaryOp.PostIncrement(converter.convert(unaryExpr.getType()), converter.convert(unaryExpr.expr));
|
||||
case PLUS -> new TargetUnaryOp.Add(converter.convert(unaryExpr.getType()), converter.convert(unaryExpr.expr));
|
||||
case POSTDECREMENT -> new TargetUnaryOp.PostDecrement(converter.convert(unaryExpr.getType()), converter.convert(unaryExpr.expr));
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(Literal literal) {
|
||||
if (literal.value instanceof Integer || literal.value instanceof Short || literal.value instanceof Byte) {
|
||||
|
||||
result = new TargetLiteral.IntLiteral((int) literal.value);
|
||||
} else if (literal.value instanceof Float) {
|
||||
result = new TargetLiteral.FloatLiteral((float) literal.value);
|
||||
} else if (literal.value instanceof Double) {
|
||||
result = new TargetLiteral.DoubleLiteral((double) literal.value);
|
||||
} else if (literal.value instanceof Long) {
|
||||
result = new TargetLiteral.LongLiteral((long) literal.value);
|
||||
} else if (literal.value instanceof Character) {
|
||||
result = new TargetLiteral.CharLiteral((char) literal.value);
|
||||
} else if (literal.value instanceof String) {
|
||||
result = new TargetLiteral.StringLiteral((String) literal.value);
|
||||
} else if (literal.value instanceof Boolean) {
|
||||
result = new TargetLiteral.BooleanLiteral((boolean) literal.value);
|
||||
} else if (literal.value == null) {
|
||||
result = new TargetLiteral.Null();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(Throw aThrow) {
|
||||
result = new TargetThrow(converter.convert(aThrow.expr));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(Ternary ternary) {
|
||||
result = new TargetTernary(converter.convert(ternary.getType()), converter.convert(ternary.cond), converter.convert(ternary.iftrue), converter.convert(ternary.iffalse));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(Switch switchStmt) {
|
||||
var cases = switchStmt.getBlocks().stream().filter(s -> !s.isDefault()).map(converter::convert).toList();
|
||||
|
||||
TargetSwitch.Case default_ = null;
|
||||
for (var block : switchStmt.getBlocks()) {
|
||||
if (block.isDefault()) {
|
||||
default_ = new TargetSwitch.Case(converter.convert((Block) block), block.isExpression);
|
||||
}
|
||||
}
|
||||
result = new TargetSwitch(converter.convert(switchStmt.getSwitch()), cases, default_ , converter.convert(switchStmt.getType()), !switchStmt.getStatement());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(SwitchBlock switchBlock) {}
|
||||
|
||||
@Override
|
||||
public void visit(SwitchLabel switchLabel) {
|
||||
result = converter.convert(switchLabel.getPattern());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(Yield aYield) {
|
||||
result = new TargetYield(converter.convert(aYield.retexpr));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(SourceFile sourceFile) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(GenericTypeVar genericTypeVar) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(GenericDeclarationList genericTypeVars) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(Field field) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(de.dhbwstuttgart.syntaxtree.Method field) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(Constructor field) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(ParameterList formalParameters) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(ClassOrInterface classOrInterface) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(RefType refType) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(SuperWildcardType superWildcardType) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(TypePlaceholder typePlaceholder) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(ExtendsWildcardType extendsWildcardType) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(GenericRefType genericRefType) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(FormalParameter aPattern) {
|
||||
result = new TargetTypePattern(converter.convert(aPattern.getType()), aPattern.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(ExpressionPattern aPattern) {
|
||||
result = converter.convert(aPattern.getExpression());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(RecordPattern aRecordPattern) {
|
||||
result = new TargetComplexPattern(
|
||||
converter.convert(aRecordPattern.getType()),
|
||||
aRecordPattern.getName(),
|
||||
aRecordPattern.getSubPattern().stream().map(x -> (TargetPattern) converter.convert(x)).toList()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(GuardedPattern aGuardedPattern) {
|
||||
result = new TargetGuard((TargetPattern) converter.convert(aGuardedPattern.getNestedPattern()), converter.convert(aGuardedPattern.getCondition()));
|
||||
}
|
||||
}
|
@ -1,218 +0,0 @@
|
||||
package de.dhbwstuttgart.target.generate;
|
||||
|
||||
import de.dhbwstuttgart.parser.SyntaxTreeGenerator.AssignToLocal;
|
||||
import de.dhbwstuttgart.syntaxtree.Method;
|
||||
import de.dhbwstuttgart.syntaxtree.StatementVisitor;
|
||||
import de.dhbwstuttgart.syntaxtree.statement.*;
|
||||
|
||||
// This visitor walks the entire tree, individual methods may be overridden
|
||||
public abstract class TracingStatementVisitor implements StatementVisitor {
|
||||
|
||||
@Override
|
||||
public void visit(ThisCall thisCall) {
|
||||
visit((MethodCall) thisCall);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(MethodCall methodCall) {
|
||||
methodCall.receiver.accept(this);
|
||||
methodCall.getArgumentList().accept(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(ArgumentList argumentList) {
|
||||
argumentList.getArguments().forEach(expr -> expr.accept(this));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(LambdaExpression lambdaExpression) {
|
||||
lambdaExpression.methodBody.accept(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(Assign assign) {
|
||||
assign.rightSide.accept(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(BinaryExpr binary) {
|
||||
binary.lexpr.accept(this);
|
||||
binary.rexpr.accept(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(BoolExpression bool) {
|
||||
bool.lexpr.accept(this);
|
||||
bool.rexpr.accept(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(Block block) {
|
||||
for (var expr : block.statements)
|
||||
expr.accept(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(CastExpr castExpr) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(EmptyStmt emptyStmt) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(FieldVar fieldVar) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(ForStmt forStmt) {
|
||||
forStmt.block.accept(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(ForEachStmt forEachStmt) {
|
||||
forEachStmt.block.accept(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(IfStmt ifStmt) {
|
||||
ifStmt.then_block.accept(this);
|
||||
if (ifStmt.else_block != null)
|
||||
ifStmt.else_block.accept(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(InstanceOf instanceOf) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(LocalVar localVar) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(LocalVarDecl localVarDecl) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(NewClass newClass) {
|
||||
this.visit((MethodCall) newClass);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(NewArray newArray) {
|
||||
newArray.expr.forEach(expr -> expr.accept(this));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(Return aReturn) {
|
||||
aReturn.retexpr.accept(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(ReturnVoid aReturn) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(Break aBreak) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(Continue aContinue) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(StaticClassName staticClassName) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(Super aSuper) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(This aThis) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WhileStmt whileStmt) {
|
||||
whileStmt.loopBlock.accept(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(DoStmt whileStmt) {
|
||||
whileStmt.loopBlock.accept(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(AssignToField assignLeftSide) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(AssignToLocal assignLeftSide) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(SuperCall superCall) {
|
||||
visit((MethodCall) superCall);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(ExpressionReceiver expressionReceiver) {
|
||||
expressionReceiver.expr.accept(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(UnaryExpr unaryExpr) {
|
||||
unaryExpr.expr.accept(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(Literal literal) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(Throw aThrow) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(Switch switchStmt) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(SwitchBlock switchBlock) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(SwitchLabel switchLabel) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(Yield aYield) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(Ternary ternary) {
|
||||
ternary.cond.accept(this);
|
||||
ternary.iftrue.accept(this);
|
||||
ternary.iffalse.accept(this);
|
||||
}
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
package de.dhbwstuttgart.target.generate;
|
||||
|
||||
import de.dhbwstuttgart.syntaxtree.ClassOrInterface;
|
||||
import de.dhbwstuttgart.syntaxtree.Method;
|
||||
import de.dhbwstuttgart.typeinference.result.ResultSet;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
final class TxGenerics extends GenerateGenerics {
|
||||
TxGenerics(ASTToTargetAST astToTargetAST, ResultSet constraints) {
|
||||
super(astToTargetAST, constraints);
|
||||
}
|
||||
|
||||
@Override
|
||||
void generics(ClassOrInterface owner, Method method, Set<Pair> result, Set<TPH> referenced) {
|
||||
eliminateInfima(result, referenced);
|
||||
eliminateInnerTypeVariables(referenced, result);
|
||||
}
|
||||
|
||||
@Override
|
||||
void generics(ClassOrInterface classOrInterface, Set<Pair> result, Set<TPH> referenced) {
|
||||
eliminateInfima(result, referenced);
|
||||
eliminateInnerTypeVariablesOfClass(classOrInterface, result, referenced);
|
||||
}
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
package de.dhbwstuttgart.target.tree;
|
||||
|
||||
import de.dhbwstuttgart.target.tree.expression.TargetPattern;
|
||||
import de.dhbwstuttgart.target.tree.expression.TargetTypePattern;
|
||||
import de.dhbwstuttgart.target.tree.type.TargetType;
|
||||
|
||||
public record MethodParameter(TargetPattern pattern) {
|
||||
public MethodParameter(TargetType type, String name) {
|
||||
this(new TargetTypePattern(type, name));
|
||||
}
|
||||
public MethodParameter withType(TargetType type) {
|
||||
return new MethodParameter(pattern.withType(type));
|
||||
}
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
package de.dhbwstuttgart.target.tree;
|
||||
|
||||
import de.dhbwstuttgart.parser.scope.JavaClassName;
|
||||
import de.dhbwstuttgart.target.tree.expression.TargetBlock;
|
||||
import de.dhbwstuttgart.target.tree.type.TargetRefType;
|
||||
import de.dhbwstuttgart.target.tree.type.TargetType;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public record TargetClass(int modifiers, JavaClassName qualifiedName, TargetType superType, Set<TargetGeneric> generics, Set<TargetGeneric> txGenerics, List<TargetType> implementingInterfaces,
|
||||
List<TargetConstructor> constructors, TargetMethod staticConstructor, List<TargetField> fields, List<TargetMethod> methods) implements TargetStructure {
|
||||
|
||||
public TargetClass(int modifiers, JavaClassName qualifiedName) {
|
||||
this(modifiers, qualifiedName, TargetType.Object, new HashSet<>(), new HashSet<>(), new ArrayList<>(), new ArrayList<>(), null, new ArrayList<>(), new ArrayList<>());
|
||||
}
|
||||
public TargetClass(int modifiers, JavaClassName qualifiedName, List<TargetType> implementingInterfaces) {
|
||||
this(modifiers, qualifiedName, TargetType.Object, new HashSet<>(), new HashSet<>(), implementingInterfaces, new ArrayList<>(), null, new ArrayList<>(), new ArrayList<>());
|
||||
}
|
||||
|
||||
public void addField(int access, TargetRefType type, String name) {
|
||||
this.fields.add(new TargetField(access, type, name));
|
||||
}
|
||||
}
|
||||
|
@ -1,24 +0,0 @@
|
||||
package de.dhbwstuttgart.target.tree;
|
||||
|
||||
import de.dhbwstuttgart.syntaxtree.Method;
|
||||
import de.dhbwstuttgart.target.tree.expression.TargetBlock;
|
||||
import de.dhbwstuttgart.target.tree.type.TargetType;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public record TargetConstructor(int access, Set<TargetGeneric> generics, Set<TargetGeneric> txGenerics, List<MethodParameter> parameters, List<MethodParameter> txParameters, TargetBlock block, TargetBlock fieldInitializer) {
|
||||
|
||||
public String getDescriptor() {
|
||||
return TargetMethod.getDescriptor(null, parameters.stream().map(mp -> mp.pattern().type()).toArray(TargetType[]::new));
|
||||
}
|
||||
|
||||
public String getSignature() {
|
||||
return TargetMethod.getSignature(generics, parameters, null);
|
||||
}
|
||||
|
||||
public String getTXSignature() {
|
||||
return TargetMethod.getSignature(txGenerics, txParameters, null);
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +0,0 @@
|
||||
package de.dhbwstuttgart.target.tree;
|
||||
|
||||
import de.dhbwstuttgart.target.tree.type.TargetType;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
|
||||
public record TargetField(int access, TargetType type, String name) {
|
||||
public boolean isStatic() {
|
||||
return (access & Opcodes.ACC_STATIC) != 0;
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +0,0 @@
|
||||
package de.dhbwstuttgart.target.tree;
|
||||
|
||||
import de.dhbwstuttgart.target.tree.type.TargetType;
|
||||
|
||||
public record TargetGeneric(String name, TargetType bound) {
|
||||
}
|
@ -1,24 +0,0 @@
|
||||
package de.dhbwstuttgart.target.tree;
|
||||
|
||||
import de.dhbwstuttgart.parser.scope.JavaClassName;
|
||||
import de.dhbwstuttgart.target.tree.type.TargetType;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public record TargetInterface(int modifiers, JavaClassName qualifiedName, Set<TargetGeneric> generics, Set<TargetGeneric> txGenerics, List<TargetMethod> methods, List<TargetType> implementingInterfaces, TargetMethod staticConstructor) implements TargetStructure {
|
||||
@Override
|
||||
public TargetType superType() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TargetConstructor> constructors() {
|
||||
return List.of();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TargetField> fields() {
|
||||
return List.of();
|
||||
}
|
||||
}
|
@ -1,80 +0,0 @@
|
||||
package de.dhbwstuttgart.target.tree;
|
||||
|
||||
import de.dhbwstuttgart.target.tree.expression.TargetBlock;
|
||||
import de.dhbwstuttgart.target.tree.expression.TargetPattern;
|
||||
import de.dhbwstuttgart.target.tree.type.TargetType;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
public record TargetMethod(int access, String name, TargetBlock block, Signature signature, Signature txSignature) {
|
||||
public record Signature(Set<TargetGeneric> generics, List<MethodParameter> parameters, TargetType returnType) {
|
||||
public String getSignature() {
|
||||
return TargetMethod.getSignature(generics, parameters, returnType);
|
||||
}
|
||||
|
||||
public String getDescriptor() {
|
||||
return TargetMethod.getDescriptor(returnType, parameters.stream().map(MethodParameter::pattern).map(TargetPattern::type).toArray(TargetType[]::new));
|
||||
}
|
||||
}
|
||||
|
||||
public static String getDescriptor(TargetType returnType, TargetType... parameters) {
|
||||
String ret = "(";
|
||||
for (var parameterType : parameters) {
|
||||
ret += parameterType.toSignature();
|
||||
}
|
||||
ret += ")";
|
||||
if (returnType == null) ret += "V";
|
||||
else ret += returnType.toSignature();
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static String getSignature(Set<TargetGeneric> generics, List<MethodParameter> parameters, TargetType returnType) {
|
||||
String ret = "";
|
||||
if (generics.size() > 0) {
|
||||
ret += "<";
|
||||
for (var generic : generics) {
|
||||
ret += generic.name() + ":" + generic.bound().toDescriptor();
|
||||
}
|
||||
ret += ">";
|
||||
}
|
||||
ret += "(";
|
||||
for (var param : parameters) {
|
||||
ret += param.pattern().type().toDescriptor();
|
||||
}
|
||||
ret += ")";
|
||||
if (returnType == null) ret += "V";
|
||||
else ret += returnType.toDescriptor();
|
||||
return ret;
|
||||
}
|
||||
|
||||
public String getDescriptor() {
|
||||
return getDescriptor(signature.returnType, signature.parameters.stream().map(mp -> mp.pattern().type()).toArray(TargetType[]::new));
|
||||
}
|
||||
|
||||
public String getSignature() {
|
||||
return getSignature(signature.generics, signature.parameters, signature.returnType);
|
||||
}
|
||||
|
||||
public String getTXSignature() {
|
||||
return getSignature(txSignature.generics, txSignature.parameters, txSignature.returnType);
|
||||
}
|
||||
|
||||
public boolean isStatic() {
|
||||
return (access & Opcodes.ACC_STATIC) != 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (!(other instanceof TargetMethod otherMethod)) return false;
|
||||
return otherMethod.signature.equals(this.signature) && otherMethod.name.equals(this.name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(name, signature);
|
||||
}
|
||||
}
|
||||
|
@ -1,16 +0,0 @@
|
||||
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.List;
|
||||
import java.util.Set;
|
||||
|
||||
public record TargetRecord(int modifiers, JavaClassName qualifiedName, Set<TargetGeneric> generics, Set<TargetGeneric> txGenerics, List<TargetType> implementingInterfaces, List<TargetConstructor> constructors, TargetMethod staticConstructor, List<TargetField> fields, List<TargetMethod> methods) implements TargetStructure {
|
||||
|
||||
public static final TargetType RECORD = new TargetRefType("java.lang.Record");
|
||||
public TargetType superType() {
|
||||
return RECORD;
|
||||
}
|
||||
}
|
@ -1,44 +0,0 @@
|
||||
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;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public interface TargetStructure {
|
||||
int modifiers();
|
||||
JavaClassName qualifiedName();
|
||||
TargetType superType();
|
||||
Set<TargetGeneric> generics();
|
||||
Set<TargetGeneric> txGenerics();
|
||||
List<TargetType> implementingInterfaces();
|
||||
List<TargetConstructor> constructors();
|
||||
|
||||
TargetMethod staticConstructor();
|
||||
|
||||
List<TargetField> fields();
|
||||
List<TargetMethod> methods();
|
||||
|
||||
default String getName() {
|
||||
return qualifiedName().toString().replaceAll("\\.", "/");
|
||||
}
|
||||
|
||||
// These methods are only meant to be used for test cases, a Class record should be immutable!
|
||||
default void addMethod(int access, String name, Set<TargetGeneric> generics, List<MethodParameter> parameterTypes, TargetType returnType, TargetBlock block) {
|
||||
this.methods().add(new TargetMethod(access, name, block, new TargetMethod.Signature(generics, parameterTypes, returnType), null));
|
||||
}
|
||||
|
||||
default void addMethod(int access, String name, List<MethodParameter> parameterTypes, TargetType returnType, TargetBlock block) {
|
||||
addMethod(access, name, Set.of(), parameterTypes, returnType, block);
|
||||
}
|
||||
|
||||
default void addConstructor(int access, Set<TargetGeneric> generics, List<MethodParameter> paramterTypes, TargetBlock block) {
|
||||
this.constructors().add(new TargetConstructor(access, generics, Set.of(), paramterTypes, List.of(), block, null));
|
||||
}
|
||||
|
||||
default void addConstructor(int access, List<MethodParameter> paramterTypes, TargetBlock block) {
|
||||
addConstructor(access, Set.of(), paramterTypes, block);
|
||||
}
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
package de.dhbwstuttgart.target.tree.expression;
|
||||
|
||||
import de.dhbwstuttgart.target.tree.type.TargetType;
|
||||
|
||||
public record TargetAssign(TargetType type, TargetExpression left, TargetExpression right) implements TargetStatementExpression {
|
||||
}
|
@ -1,85 +0,0 @@
|
||||
package de.dhbwstuttgart.target.tree.expression;
|
||||
|
||||
import de.dhbwstuttgart.target.tree.expression.TargetExpression;
|
||||
import de.dhbwstuttgart.target.tree.type.TargetType;
|
||||
|
||||
public sealed interface TargetBinaryOp extends TargetExpression {
|
||||
TargetExpression left();
|
||||
|
||||
TargetExpression right();
|
||||
|
||||
// Arithmetic
|
||||
record Add(TargetType type, TargetExpression left, TargetExpression right) implements TargetBinaryOp {
|
||||
}
|
||||
|
||||
record Sub(TargetType type, TargetExpression left, TargetExpression right) implements TargetBinaryOp {
|
||||
}
|
||||
|
||||
record Div(TargetType type, TargetExpression left, TargetExpression right) implements TargetBinaryOp {
|
||||
}
|
||||
|
||||
record Mul(TargetType type, TargetExpression left, TargetExpression right) implements TargetBinaryOp {
|
||||
}
|
||||
|
||||
record Rem(TargetType type, TargetExpression left, TargetExpression right) implements TargetBinaryOp {
|
||||
}
|
||||
|
||||
// Bitwise
|
||||
record BAnd(TargetType type, TargetExpression left, TargetExpression right) implements TargetBinaryOp {
|
||||
}
|
||||
|
||||
record BOr(TargetType type, TargetExpression left, TargetExpression right) implements TargetBinaryOp {
|
||||
}
|
||||
|
||||
record XOr(TargetType type, TargetExpression left, TargetExpression right) implements TargetBinaryOp {
|
||||
}
|
||||
|
||||
record Shl(TargetType type, TargetExpression left, TargetExpression right) implements TargetBinaryOp {
|
||||
}
|
||||
|
||||
record Shr(TargetType type, TargetExpression left, TargetExpression right) implements TargetBinaryOp {
|
||||
}
|
||||
|
||||
record UShr(TargetType type, TargetExpression left, TargetExpression right) implements TargetBinaryOp {
|
||||
}
|
||||
|
||||
// Conditional
|
||||
record And(TargetType type, TargetExpression left, TargetExpression right) implements TargetBinaryOp {
|
||||
}
|
||||
|
||||
record Or(TargetType type, TargetExpression left, TargetExpression right) implements TargetBinaryOp {
|
||||
}
|
||||
|
||||
record Instof(TargetType type, TargetExpression left, TargetExpression right) implements TargetBinaryOp {
|
||||
}
|
||||
|
||||
sealed interface TargetRelationalOp extends TargetBinaryOp {
|
||||
@Override
|
||||
default TargetType type() {
|
||||
return TargetType.Boolean;
|
||||
}
|
||||
|
||||
TargetType exprType();
|
||||
}
|
||||
|
||||
// Comparison
|
||||
// exprType is the type that both arguments get converted to before comparison
|
||||
record Equal(TargetType exprType, TargetExpression left, TargetExpression right) implements TargetRelationalOp {
|
||||
}
|
||||
|
||||
record Greater(TargetType exprType, TargetExpression left, TargetExpression right) implements TargetRelationalOp {
|
||||
}
|
||||
|
||||
record GreaterOrEqual(TargetType exprType, TargetExpression left, TargetExpression right) implements TargetRelationalOp {
|
||||
}
|
||||
|
||||
record Less(TargetType exprType, TargetExpression left, TargetExpression right) implements TargetRelationalOp {
|
||||
}
|
||||
|
||||
record LessOrEqual(TargetType exprType, TargetExpression left, TargetExpression right) implements TargetRelationalOp {
|
||||
}
|
||||
|
||||
record NotEqual(TargetType exprType, TargetExpression left, TargetExpression right) implements TargetRelationalOp {
|
||||
}
|
||||
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
package de.dhbwstuttgart.target.tree.expression;
|
||||
|
||||
import de.dhbwstuttgart.target.tree.type.TargetType;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public record TargetBlock(List<TargetExpression> statements) implements TargetExpression {
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
package de.dhbwstuttgart.target.tree.expression;
|
||||
|
||||
import de.dhbwstuttgart.target.tree.type.TargetType;
|
||||
|
||||
// TODO This needs a label
|
||||
public record TargetBreak() implements TargetExpression {
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
package de.dhbwstuttgart.target.tree.expression;
|
||||
|
||||
import de.dhbwstuttgart.target.tree.type.TargetType;
|
||||
|
||||
public record TargetCast(TargetType type, TargetExpression expr) implements TargetExpression {
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
package de.dhbwstuttgart.target.tree.expression;
|
||||
|
||||
import de.dhbwstuttgart.target.tree.type.TargetType;
|
||||
|
||||
public record TargetClassName(TargetType type) implements TargetExpression {
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
package de.dhbwstuttgart.target.tree.expression;
|
||||
|
||||
import de.dhbwstuttgart.target.tree.type.TargetType;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public record TargetComplexPattern(TargetType type, String name, List<TargetPattern> subPatterns) implements TargetPattern {
|
||||
@Override
|
||||
public TargetComplexPattern withType(TargetType type) {
|
||||
return new TargetComplexPattern(type, name, subPatterns);
|
||||
}
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
package de.dhbwstuttgart.target.tree.expression;
|
||||
|
||||
import de.dhbwstuttgart.target.tree.type.TargetType;
|
||||
|
||||
public record TargetContinue() implements TargetExpression {
|
||||
}
|
@ -1,4 +0,0 @@
|
||||
package de.dhbwstuttgart.target.tree.expression;
|
||||
|
||||
public record TargetDo(TargetExpression cond, TargetExpression body) implements TargetExpression {
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
package de.dhbwstuttgart.target.tree.expression;
|
||||
|
||||
import de.dhbwstuttgart.target.tree.type.*;
|
||||
|
||||
public sealed interface TargetExpression
|
||||
permits TargetBinaryOp, TargetBlock, TargetBreak, TargetCast, TargetClassName, TargetContinue, TargetDo, TargetFieldVar, TargetFor, TargetForEach, TargetIf, TargetInstanceOf, TargetLambdaExpression, TargetLiteral, TargetLocalVar, TargetPattern, TargetReturn, TargetStatementExpression, TargetSuper, TargetSwitch, TargetTernary, TargetThis, TargetThrow, TargetUnaryOp, TargetVarDecl, TargetWhile, TargetYield {
|
||||
|
||||
default TargetType type() {
|
||||
return null;
|
||||
};
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
package de.dhbwstuttgart.target.tree.expression;
|
||||
|
||||
import de.dhbwstuttgart.target.tree.type.TargetRefType;
|
||||
import de.dhbwstuttgart.target.tree.type.TargetType;
|
||||
|
||||
public record TargetFieldVar(TargetType type, TargetType owner, boolean isStatic, TargetExpression left, String right) implements TargetExpression {
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
package de.dhbwstuttgart.target.tree.expression;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public record TargetFor(List<TargetExpression> init, TargetExpression termination, List<TargetExpression> increment, TargetExpression body) implements TargetExpression {
|
||||
}
|
@ -1,4 +0,0 @@
|
||||
package de.dhbwstuttgart.target.tree.expression;
|
||||
|
||||
public record TargetForEach(TargetExpression vardecl, TargetExpression expression, TargetExpression body) implements TargetExpression {
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
package de.dhbwstuttgart.target.tree.expression;
|
||||
|
||||
import de.dhbwstuttgart.target.tree.type.TargetType;
|
||||
|
||||
public record TargetGuard(TargetPattern inner, TargetExpression expression) implements TargetPattern {
|
||||
@Override
|
||||
public TargetGuard withType(TargetType type) {
|
||||
return new TargetGuard(inner.withType(type), expression);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TargetType type() {
|
||||
return inner.type();
|
||||
}
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
package de.dhbwstuttgart.target.tree.expression;
|
||||
|
||||
import de.dhbwstuttgart.target.tree.type.TargetType;
|
||||
|
||||
public record TargetIf(TargetExpression cond, TargetExpression if_body, TargetExpression else_body) implements TargetExpression {
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
package de.dhbwstuttgart.target.tree.expression;
|
||||
|
||||
import de.dhbwstuttgart.syntaxtree.statement.Expression;
|
||||
import de.dhbwstuttgart.target.tree.type.TargetType;
|
||||
|
||||
public record TargetInstanceOf(TargetExpression left, TargetExpression right) implements TargetExpression {
|
||||
|
||||
@Override
|
||||
public TargetType type() {
|
||||
return TargetType.Boolean;
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
package de.dhbwstuttgart.target.tree.expression;
|
||||
|
||||
import de.dhbwstuttgart.target.tree.MethodParameter;
|
||||
import de.dhbwstuttgart.target.tree.TargetField;
|
||||
import de.dhbwstuttgart.target.tree.TargetMethod;
|
||||
import de.dhbwstuttgart.target.tree.type.TargetType;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public record TargetLambdaExpression(TargetType type, List<MethodParameter> captures, TargetMethod.Signature signature, TargetBlock block) implements TargetExpression {
|
||||
}
|
@ -1,68 +0,0 @@
|
||||
package de.dhbwstuttgart.target.tree.expression;
|
||||
|
||||
import de.dhbwstuttgart.target.tree.type.TargetType;
|
||||
|
||||
public sealed interface TargetLiteral extends TargetExpression {
|
||||
Object value();
|
||||
|
||||
record BooleanLiteral(Boolean value) implements TargetLiteral {
|
||||
@Override
|
||||
public TargetType type() {
|
||||
return TargetType.Boolean;
|
||||
}
|
||||
}
|
||||
|
||||
record CharLiteral(Character value) implements TargetLiteral {
|
||||
@Override
|
||||
public TargetType type() {
|
||||
return TargetType.Char;
|
||||
}
|
||||
}
|
||||
|
||||
record IntLiteral(Integer value) implements TargetLiteral {
|
||||
@Override
|
||||
public TargetType type() {
|
||||
return TargetType.Integer;
|
||||
}
|
||||
}
|
||||
|
||||
record LongLiteral(Long value) implements TargetLiteral {
|
||||
@Override
|
||||
public TargetType type() {
|
||||
return TargetType.Long;
|
||||
}
|
||||
}
|
||||
|
||||
record FloatLiteral(Float value) implements TargetLiteral {
|
||||
@Override
|
||||
public TargetType type() {
|
||||
return TargetType.Float;
|
||||
}
|
||||
}
|
||||
|
||||
record DoubleLiteral(Double value) implements TargetLiteral {
|
||||
@Override
|
||||
public TargetType type() {
|
||||
return TargetType.Double;
|
||||
}
|
||||
}
|
||||
|
||||
record StringLiteral(String value) implements TargetLiteral {
|
||||
@Override
|
||||
public TargetType type() {
|
||||
return TargetType.String;
|
||||
}
|
||||
}
|
||||
|
||||
record Null() implements TargetLiteral {
|
||||
@Override
|
||||
public TargetType type() {
|
||||
return TargetType.Object;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object value() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
package de.dhbwstuttgart.target.tree.expression;
|
||||
|
||||
import de.dhbwstuttgart.target.tree.type.TargetType;
|
||||
|
||||
public record TargetLocalVar(TargetType type, String name) implements TargetExpression {
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
package de.dhbwstuttgart.target.tree.expression;
|
||||
|
||||
import de.dhbwstuttgart.target.tree.TargetMethod;
|
||||
import de.dhbwstuttgart.target.tree.type.TargetType;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public record TargetMethodCall(TargetType type, TargetType returnType, List<TargetType> parameterTypes, TargetExpression expr, List<TargetExpression> args, TargetType owner, String name, boolean isStatic, boolean isInterface, boolean isPrivate) implements TargetStatementExpression {
|
||||
public TargetMethodCall(TargetType type, TargetExpression expr, List<TargetExpression> args, TargetType owner, String name, boolean isStatic, boolean isInterface, boolean isPrivate) {
|
||||
this(type, type, args.stream().map(TargetExpression::type).toList(), expr, args, owner, name, isStatic, isInterface, isPrivate);
|
||||
}
|
||||
|
||||
|
||||
public String getDescriptor() {
|
||||
return TargetMethod.getDescriptor(returnType, parameterTypes.toArray(TargetType[]::new));
|
||||
}
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
package de.dhbwstuttgart.target.tree.expression;
|
||||
|
||||
import de.dhbwstuttgart.target.tree.TargetMethod;
|
||||
import de.dhbwstuttgart.target.tree.type.TargetType;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public record TargetNew(TargetType type, List<TargetType> signature, List<TargetExpression> params) implements TargetStatementExpression {
|
||||
public String getDescriptor() {
|
||||
return TargetMethod.getDescriptor(null, signature.toArray(TargetType[]::new));
|
||||
}
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
package de.dhbwstuttgart.target.tree.expression;
|
||||
|
||||
import de.dhbwstuttgart.target.tree.type.TargetType;
|
||||
|
||||
public sealed interface TargetPattern extends TargetExpression permits TargetComplexPattern, TargetGuard, TargetTypePattern {
|
||||
default String name() {
|
||||
return null;
|
||||
}
|
||||
|
||||
TargetPattern withType(TargetType type);
|
||||
|
||||
TargetType type();
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
package de.dhbwstuttgart.target.tree.expression;
|
||||
|
||||
import de.dhbwstuttgart.target.tree.type.TargetType;
|
||||
|
||||
public record TargetReturn(TargetExpression expression) implements TargetExpression {
|
||||
}
|
@ -1,4 +0,0 @@
|
||||
package de.dhbwstuttgart.target.tree.expression;
|
||||
|
||||
public sealed interface TargetStatementExpression extends TargetExpression permits TargetAssign, TargetMethodCall, TargetNew, TargetUnaryOp.PostDecrement, TargetUnaryOp.PostIncrement, TargetUnaryOp.PreDecrement, TargetUnaryOp.PreIncrement {
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
package de.dhbwstuttgart.target.tree.expression;
|
||||
|
||||
import de.dhbwstuttgart.target.tree.type.TargetType;
|
||||
|
||||
public record TargetSuper(TargetType type) implements TargetExpression {
|
||||
}
|
@ -1,30 +0,0 @@
|
||||
package de.dhbwstuttgart.target.tree.expression;
|
||||
|
||||
import de.dhbwstuttgart.target.tree.type.TargetType;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public record TargetSwitch(TargetExpression expr, List<Case> cases, Case default_, TargetType type, boolean isExpression) implements TargetExpression {
|
||||
|
||||
public TargetSwitch(TargetExpression expr, List<Case> cases, Case default_) {
|
||||
this(expr, cases, default_, null, false);
|
||||
}
|
||||
|
||||
public TargetSwitch(TargetExpression expr, List<Case> cases, Case default_, TargetType type) {
|
||||
this(expr, cases, default_, type, true);
|
||||
}
|
||||
|
||||
public TargetSwitch(TargetExpression expr, List<Case> cases, Case default_, boolean isExpression) {
|
||||
this(expr, cases, default_, null, isExpression);
|
||||
}
|
||||
|
||||
public record Case(List<TargetExpression> labels, TargetBlock body, boolean isSingleExpression) {
|
||||
public Case(List<TargetExpression> labels, TargetBlock body) {
|
||||
this(labels, body, false);
|
||||
}
|
||||
public Case(TargetBlock body, boolean isSingleExpression) {
|
||||
this(List.of(), body, isSingleExpression);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
package de.dhbwstuttgart.target.tree.expression;
|
||||
|
||||
import de.dhbwstuttgart.target.tree.type.TargetType;
|
||||
|
||||
public record TargetTernary(TargetType type, TargetExpression cond, TargetExpression iftrue, TargetExpression iffalse) implements TargetExpression {
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
package de.dhbwstuttgart.target.tree.expression;
|
||||
|
||||
import de.dhbwstuttgart.target.tree.type.TargetType;
|
||||
|
||||
public record TargetThis(TargetType type) implements TargetExpression {
|
||||
}
|
@ -1,4 +0,0 @@
|
||||
package de.dhbwstuttgart.target.tree.expression;
|
||||
|
||||
public record TargetThrow(TargetExpression expr) implements TargetExpression {
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
package de.dhbwstuttgart.target.tree.expression;
|
||||
|
||||
import de.dhbwstuttgart.target.tree.type.TargetType;
|
||||
|
||||
public record TargetTypePattern(TargetType type, String name) implements TargetPattern {
|
||||
@Override
|
||||
public TargetTypePattern withType(TargetType type) {
|
||||
return new TargetTypePattern(type, name);
|
||||
}
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
package de.dhbwstuttgart.target.tree.expression;
|
||||
|
||||
import de.dhbwstuttgart.target.tree.type.TargetType;
|
||||
|
||||
public sealed interface TargetUnaryOp extends TargetExpression {
|
||||
TargetExpression expr();
|
||||
|
||||
record Negate(TargetType type, TargetExpression expr) implements TargetUnaryOp {}
|
||||
record Add(TargetType type, TargetExpression expr) implements TargetUnaryOp {}
|
||||
record Not(TargetType type, TargetExpression expr) implements TargetUnaryOp {}
|
||||
|
||||
record PreIncrement(TargetType type, TargetExpression expr) implements TargetStatementExpression, TargetUnaryOp {}
|
||||
record PostIncrement(TargetType type, TargetExpression expr) implements TargetStatementExpression, TargetUnaryOp {}
|
||||
record PreDecrement(TargetType type, TargetExpression expr) implements TargetStatementExpression, TargetUnaryOp {}
|
||||
record PostDecrement(TargetType type, TargetExpression expr) implements TargetStatementExpression, TargetUnaryOp {}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
package de.dhbwstuttgart.target.tree.expression;
|
||||
|
||||
import de.dhbwstuttgart.target.tree.type.TargetType;
|
||||
|
||||
public record TargetVarDecl(TargetType varType, String name, TargetExpression value) implements TargetExpression {
|
||||
|
||||
@Override
|
||||
public TargetType type() {
|
||||
return null;
|
||||
}
|
||||
}
|
@ -1,4 +0,0 @@
|
||||
package de.dhbwstuttgart.target.tree.expression;
|
||||
|
||||
public record TargetWhile(TargetExpression cond, TargetExpression body) implements TargetExpression {
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
package de.dhbwstuttgart.target.tree.expression;
|
||||
|
||||
import de.dhbwstuttgart.target.tree.type.TargetType;
|
||||
|
||||
public record TargetYield(TargetExpression expression) implements TargetExpression {
|
||||
@Override
|
||||
public TargetType type() {
|
||||
return expression.type();
|
||||
}
|
||||
}
|
@ -1,24 +0,0 @@
|
||||
package de.dhbwstuttgart.target.tree.type;
|
||||
|
||||
public record TargetExtendsWildcard(TargetType innerType) implements TargetType {
|
||||
@Override
|
||||
public String toSignature() {
|
||||
return innerType.toSignature();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toDescriptor() {
|
||||
return "+" + innerType.toDescriptor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getInternalName() {
|
||||
return innerType.getInternalName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return innerType.name();
|
||||
}
|
||||
}
|
||||
|
@ -1,41 +0,0 @@
|
||||
package de.dhbwstuttgart.target.tree.type;
|
||||
|
||||
import de.dhbwstuttgart.bytecode.FunNGenerator;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public record TargetFunNType(String name, List<TargetType> funNParams, List<TargetType> params, int returnArguments) implements TargetSpecializedType {
|
||||
|
||||
public static TargetFunNType fromParams(List<TargetType> params, int returnArguments) {
|
||||
return fromParams(params, params, returnArguments);
|
||||
}
|
||||
|
||||
public static TargetFunNType fromParams(List<TargetType> params, List<TargetType> realParams, int returnArguments) {
|
||||
var name = FunNGenerator.getSpecializedClassName(FunNGenerator.getArguments(params), FunNGenerator.getReturnType(params));
|
||||
return new TargetFunNType(name, params, realParams, returnArguments);
|
||||
}
|
||||
|
||||
public String toMethodDescriptor() {
|
||||
var res = "(";
|
||||
for (var i = 0; i < funNParams.size() - 1; i++) {
|
||||
res += "Ljava/lang/Object;";
|
||||
}
|
||||
res += ")";
|
||||
if (returnArguments > 0) {
|
||||
res += "Ljava/lang/Object;";
|
||||
} else {
|
||||
res += "V";
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getInternalName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toSignature() {
|
||||
return "L" + getInternalName() + ";";
|
||||
}
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
package de.dhbwstuttgart.target.tree.type;
|
||||
|
||||
public record TargetGenericType(String name) implements TargetType {
|
||||
@Override
|
||||
public String toSignature() {
|
||||
return "Ljava/lang/Object;"; // TODO Use bounds for this?
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toDescriptor() {
|
||||
return "T" + getInternalName() + ";";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getInternalName() {
|
||||
return name;
|
||||
}
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
package de.dhbwstuttgart.target.tree.type;
|
||||
|
||||
public record TargetPrimitiveType(String name) implements TargetType {
|
||||
|
||||
@Override
|
||||
public String toSignature() {
|
||||
return getInternalName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toDescriptor() {
|
||||
return toSignature();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getInternalName() {
|
||||
return name;
|
||||
}
|
||||
}
|
@ -1,33 +0,0 @@
|
||||
package de.dhbwstuttgart.target.tree.type;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
public record TargetRefType(String name, List<TargetType> params) implements TargetSpecializedType {
|
||||
public TargetRefType(String name) {
|
||||
this(name, List.of());
|
||||
}
|
||||
|
||||
public String getInternalName() {
|
||||
return this.name.replaceAll("\\.", "/");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toSignature() {
|
||||
return "L" + getInternalName() + ";";
|
||||
}
|
||||
|
||||
// Type erasure means we need to override hashCode and equals to only consider the name
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hashCode(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (other instanceof TargetRefType refType) {
|
||||
return refType.name.equals(name);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
package de.dhbwstuttgart.target.tree.type;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public sealed interface TargetSpecializedType extends TargetType permits TargetFunNType, TargetRefType {
|
||||
List<TargetType> params();
|
||||
|
||||
@Override
|
||||
default String toDescriptor() {
|
||||
String ret = "L" + getInternalName();
|
||||
if (params().size() > 0) {
|
||||
ret += "<";
|
||||
for (var param : params()) {
|
||||
ret += param.toDescriptor();
|
||||
}
|
||||
ret += ">";
|
||||
}
|
||||
ret += ";";
|
||||
return ret;
|
||||
}
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
package de.dhbwstuttgart.target.tree.type;
|
||||
|
||||
public record TargetSuperWildcard(TargetType innerType) implements TargetType {
|
||||
@Override
|
||||
public String toSignature() {
|
||||
return innerType.toSignature();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toDescriptor() {
|
||||
return "-" + innerType.toDescriptor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getInternalName() {
|
||||
return innerType.getInternalName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return innerType.name();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,73 +0,0 @@
|
||||
package de.dhbwstuttgart.target.tree.type;
|
||||
|
||||
import de.dhbwstuttgart.syntaxtree.type.RefType;
|
||||
|
||||
public sealed interface TargetType
|
||||
permits TargetExtendsWildcard, TargetGenericType, TargetSpecializedType, TargetSuperWildcard, TargetPrimitiveType {
|
||||
|
||||
// Builtin types
|
||||
TargetRefType Boolean = new TargetRefType("java.lang.Boolean");
|
||||
TargetRefType Char = new TargetRefType("java.lang.Character");
|
||||
TargetRefType Byte = new TargetRefType("java.lang.Byte");
|
||||
TargetRefType Short = new TargetRefType("java.lang.Short");
|
||||
TargetRefType Integer = new TargetRefType("java.lang.Integer");
|
||||
TargetRefType Long = new TargetRefType("java.lang.Long");
|
||||
TargetRefType Float = new TargetRefType("java.lang.Float");
|
||||
TargetRefType Double = new TargetRefType("java.lang.Double");
|
||||
TargetRefType String = new TargetRefType("java.lang.String");
|
||||
TargetRefType Object = new TargetRefType("java.lang.Object");
|
||||
|
||||
// Builtin types
|
||||
TargetPrimitiveType boolean_ = new TargetPrimitiveType("Z");
|
||||
TargetPrimitiveType char_ = new TargetPrimitiveType("C");
|
||||
TargetPrimitiveType byte_ = new TargetPrimitiveType("B");
|
||||
TargetPrimitiveType short_ = new TargetPrimitiveType("S");
|
||||
TargetPrimitiveType int_ = new TargetPrimitiveType("I");
|
||||
TargetPrimitiveType long_ = new TargetPrimitiveType("J");
|
||||
TargetPrimitiveType float_ = new TargetPrimitiveType("F");
|
||||
TargetPrimitiveType double_ = new TargetPrimitiveType("D");
|
||||
|
||||
static TargetType toPrimitive(TargetType type) {
|
||||
if (type.equals(Boolean)) return boolean_;
|
||||
if (type.equals(Char)) return char_;
|
||||
if (type.equals(Byte)) return byte_;
|
||||
if (type.equals(Short)) return short_;
|
||||
if (type.equals(Integer)) return int_;
|
||||
if (type.equals(Long)) return long_;
|
||||
if (type.equals(Float)) return float_;
|
||||
if (type.equals(Double)) return double_;
|
||||
return type;
|
||||
}
|
||||
|
||||
static TargetType toPrimitive(RefType type) {
|
||||
return switch(type.getName().toString()) {
|
||||
case "java.lang.Boolean" -> boolean_;
|
||||
case "java.lang.Character" -> char_;
|
||||
case "java.lang.Byte" -> byte_;
|
||||
case "java.lang.Short" -> short_;
|
||||
case "java.lang.Integer" -> int_;
|
||||
case "java.lang.Long" -> long_;
|
||||
case "java.lang.Float" -> float_;
|
||||
case "java.lang.Double" -> double_;
|
||||
default -> null;
|
||||
};
|
||||
}
|
||||
|
||||
static TargetType toWrapper(TargetType f) {
|
||||
if (f.equals(boolean_)) return Boolean;
|
||||
if (f.equals(char_)) return Char;
|
||||
if (f.equals(byte_)) return Byte;
|
||||
if (f.equals(short_)) return Short;
|
||||
if (f.equals(int_)) return Integer;
|
||||
if (f.equals(long_)) return Long;
|
||||
if (f.equals(float_)) return Float;
|
||||
if (f.equals(double_)) return Double;
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
String toSignature();
|
||||
String toDescriptor();
|
||||
String getInternalName();
|
||||
String name();
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
package de.dhbwstuttgart.typedeployment;
|
||||
|
||||
public enum KindOfTypeInsertPoint {
|
||||
NORMAL_INSERT,
|
||||
GENERIC_CLASS_INSERT,
|
||||
GENERERIC_METHOD_INSERT
|
||||
}
|
@ -1,82 +0,0 @@
|
||||
package de.dhbwstuttgart.typedeployment;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import org.antlr.v4.parse.BlockSetTransformer.setAlt_return;
|
||||
|
||||
import de.dhbwstuttgart.syntaxtree.statement.This;
|
||||
import de.dhbwstuttgart.typeinference.result.ResultPair;
|
||||
|
||||
public class TypeInsert {
|
||||
/**
|
||||
* point wird hauptsächlich zur Anzeige einer Annotation im Eclipse-plugin benutzt.
|
||||
*/
|
||||
public final TypeInsertPoint point;
|
||||
Set<TypeInsertPoint> inserts;
|
||||
ResultPair<?, ?> resultPair;
|
||||
|
||||
public TypeInsert(TypeInsertPoint point, Set<TypeInsertPoint> additionalPoints, ResultPair<?, ?> resultPair){
|
||||
this.point = point;
|
||||
inserts = additionalPoints;
|
||||
this.resultPair = resultPair;
|
||||
}
|
||||
|
||||
public String insert(String intoSource){
|
||||
List<TypeInsertPoint> offsets = new ArrayList<>();
|
||||
String ret = intoSource;
|
||||
|
||||
List<TypeInsertPoint> insertsSorted = new ArrayList<>();
|
||||
insertsSorted.add(point);
|
||||
insertsSorted.addAll(inserts);
|
||||
Collections.sort(insertsSorted, new TypeInsertPoint.TypeInsertPointPositionComparator().reversed());
|
||||
|
||||
for(TypeInsertPoint insertPoint : insertsSorted) {
|
||||
ret = insertPoint.insert(ret, new ArrayList<>());
|
||||
offsets.add(insertPoint);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public String getInsertString(){
|
||||
return point.getInsertString();
|
||||
}
|
||||
|
||||
public ResultPair<?, ?> getResultPair() {
|
||||
return this.resultPair;
|
||||
}
|
||||
|
||||
/* PL 2018-06-18
|
||||
* Zwei TypeInsert's sind gleich, wenn ihre point's und ihre inserts' gleich sind
|
||||
* eingefuegt damit man TypeReplaceMarker vergleichen kann
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
public boolean equals(Object obj) {
|
||||
if(!(obj instanceof TypeInsert)) {
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
return ((TypeInsert)obj).point.equals(this.point);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public Set<TypeInsertPoint> getAdditionalPoints() {
|
||||
TypeInsertPoint.TypeInsertPointPositionComparator comparator = new TypeInsertPoint.TypeInsertPointPositionComparator();
|
||||
TreeSet<TypeInsertPoint> result = new TreeSet<>(comparator.reversed());
|
||||
result.addAll(inserts);
|
||||
return result;
|
||||
}
|
||||
|
||||
public Set<TypeInsertPoint> getAdditionalPointsUnsorted() {
|
||||
return inserts;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return point.toString();
|
||||
}
|
||||
}
|
@ -1,204 +0,0 @@
|
||||
package de.dhbwstuttgart.typedeployment;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
|
||||
import de.dhbwstuttgart.target.generate.GenerateGenerics;
|
||||
import de.dhbwstuttgart.target.generate.GenericsResult;
|
||||
import de.dhbwstuttgart.target.generate.GenericsResultSet;
|
||||
import de.dhbwstuttgart.typeinference.result.*;
|
||||
import org.antlr.v4.runtime.Token;
|
||||
|
||||
import de.dhbwstuttgart.syntaxtree.ClassOrInterface;
|
||||
import de.dhbwstuttgart.syntaxtree.Method;
|
||||
import de.dhbwstuttgart.syntaxtree.SourceFile;
|
||||
import de.dhbwstuttgart.syntaxtree.type.ExtendsWildcardType;
|
||||
import de.dhbwstuttgart.syntaxtree.type.GenericRefType;
|
||||
import de.dhbwstuttgart.syntaxtree.type.RefType;
|
||||
import de.dhbwstuttgart.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric;
|
||||
import de.dhbwstuttgart.syntaxtree.type.SuperWildcardType;
|
||||
import de.dhbwstuttgart.syntaxtree.type.TypePlaceholder;
|
||||
|
||||
/**
|
||||
* TODO:
|
||||
* Falls in Feldern Generics entstehen, dann werden diese als Klassenparameter eingesetzt
|
||||
* Für die Instanzierung von Klassen kann man dann beispielsweise nur noch den Diamond-Operator verwenden
|
||||
*
|
||||
* Es müssen zu einem TPH alle in Beziehung stehenden Constraints gefunden werden
|
||||
*
|
||||
* Anmekung: Es wird nur ein RefType gleichzeitug eingesetzt.
|
||||
* Steht dieser mit anderen Typen in Verbindung, so müssen diese nicht eingesetzt werden
|
||||
* im Result set können nur TPHs mit <. Beziehung stehen
|
||||
* Steht ein Typ A über TPHs mit anderen Typen B in Verbindung, so lassen sich diese auch im nächsten Durchgang
|
||||
* inferieren, wenn A bereits eingesetzt wurde. Es werden dann eben zusätzliche Generics entstehen
|
||||
*/
|
||||
public class TypeInsertFactory {
|
||||
|
||||
public static Set<TypeInsert> createTypeInsertPoints(SourceFile forSourcefile, ResultSet withResults, GenericsResult generics) {
|
||||
return new TypeInsertPlacer().getTypeInserts(forSourcefile, withResults, generics);
|
||||
}
|
||||
|
||||
public static TypeInsert createInsertPoints(RefTypeOrTPHOrWildcardOrGeneric type, Token offset, ClassOrInterface cl, Method m,
|
||||
ResultSet resultSet, GenericsResultSet constraints, GenericsResultSet classConstraints) {
|
||||
|
||||
/* PL 2020-04-11 auskommentiert
|
||||
* try {
|
||||
*/
|
||||
ResolvedType resolvedType = resultSet.resolveType(type);
|
||||
TypeInsertPoint insertPoint = new TypeInsertPoint(offset,
|
||||
new TypeToInsertString(resolvedType.resolvedType, constraints, classConstraints).insert, KindOfTypeInsertPoint.NORMAL_INSERT);
|
||||
/* PL 2020-04-11 auskommentiert
|
||||
List<GenericGenratorResultForSourceFile> simplifyResults = JavaTXCompiler.INSTANCE.getGeneratedGenericResultsForAllSourceFiles(newResults);
|
||||
for (GenericGenratorResultForSourceFile simplifyResultsEntries : simplifyResults) {
|
||||
GenericsGeneratorResultForClass genericResultsForClass = simplifyResultsEntries.getSimplifyResultsByName(cl.getClassName());
|
||||
return new TypeInsert(insertPoint, createGenericInsert(genericResultsForClass, cl, m, resultSet, offset), resolvedType.getResultPair());
|
||||
}
|
||||
|
||||
return new TypeInsert(insertPoint, new HashSet<>(), resolvedType.getResultPair());
|
||||
*/
|
||||
//GenericsGeneratorResultForClass genericResultsForClass = genericResult.getSimplifyResultsByName("", cl.getClassName().toString());
|
||||
return new TypeInsert(insertPoint, createGenericInsert(constraints, classConstraints, cl, m, resultSet, offset), resolvedType.getResultPair());
|
||||
|
||||
/* PL 2020-04-11 auskommentiert
|
||||
} catch (ClassNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
private static synchronized Set<TypeInsertPoint> createGenericInsert(GenericsResultSet methodConstraints, GenericsResultSet classConstraints,ClassOrInterface cl, Method m, ResultSet resultSet, Token mOffset){
|
||||
Set<TypeInsertPoint> result = createGenericClassInserts(classConstraints, cl);
|
||||
|
||||
if (m != null) {
|
||||
//List<GenericsGeneratorResult> methodConstraints = genericResult.getMethodConstraintsByID(MethodUtility.createID(resolver, m));
|
||||
result.addAll(createMethodConstraints(methodConstraints, m.getOffset() != null ? m.getOffset() : mOffset));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static Set<TypeInsertPoint> createMethodConstraints(GenericsResultSet constraints, Token mOffset) {
|
||||
Set<TypeInsertPoint> result = new HashSet<>();
|
||||
Token offset = mOffset;
|
||||
|
||||
if (constraints.size() == 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
String insert = " <";
|
||||
|
||||
for (var genericInsertConstraint : constraints) {
|
||||
if (genericInsertConstraint instanceof GenerateGenerics.PairEQ peq) {
|
||||
insert += peq.left.resolve().getName();
|
||||
} else if (genericInsertConstraint instanceof GenerateGenerics.PairLT psm) {
|
||||
insert += psm.left.resolve().getName() + " extends " + psm.right.resolve().getName();
|
||||
}
|
||||
insert += ", ";
|
||||
}
|
||||
|
||||
insert = insert.substring(0, insert.length() -2);
|
||||
insert += ">";
|
||||
|
||||
result.add(new TypeInsertPoint(offset, insert, KindOfTypeInsertPoint.GENERERIC_METHOD_INSERT));
|
||||
return result;
|
||||
}
|
||||
|
||||
private static Set<TypeInsertPoint> createGenericClassInserts(GenericsResultSet classConstraints, ClassOrInterface cl) {
|
||||
Set<TypeInsertPoint> result = new HashSet<>();
|
||||
Token offset = cl.getGenerics().getOffset();
|
||||
|
||||
if (classConstraints == null || classConstraints.size() == 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
String insert = " <";
|
||||
|
||||
for (var genericInsertConstraint : classConstraints) {
|
||||
if (genericInsertConstraint instanceof GenerateGenerics.PairEQ peq) {
|
||||
insert += peq.left.resolve().getName();
|
||||
} else if (genericInsertConstraint instanceof GenerateGenerics.PairLT psm) {
|
||||
insert += psm.left.resolve().getName() + " extends " + psm.right.resolve().getName();
|
||||
}
|
||||
insert += ", ";
|
||||
}
|
||||
|
||||
insert = insert.substring(0, insert.length() -2);
|
||||
insert += ">";
|
||||
|
||||
result.add(new TypeInsertPoint(offset, insert, KindOfTypeInsertPoint.GENERIC_CLASS_INSERT));
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
class TypeToInsertString implements ResultSetVisitor{
|
||||
String insert = "";
|
||||
private GenericsResultSet constraints;
|
||||
private GenericsResultSet classConstraints;
|
||||
|
||||
|
||||
TypeToInsertString(RefTypeOrTPHOrWildcardOrGeneric type, GenericsResultSet constraints, GenericsResultSet classConstraints){
|
||||
this.constraints = constraints;
|
||||
this.classConstraints = classConstraints;
|
||||
type.accept(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(PairTPHsmallerTPH p) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(PairTPHequalRefTypeOrWildcardType p) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(PairTPHEqualTPH p) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(RefType resolved) {
|
||||
insert = resolved.getName().toString();
|
||||
if(resolved.getParaList().size() > 0){
|
||||
insert += "<";
|
||||
Iterator<RefTypeOrTPHOrWildcardOrGeneric> iterator = resolved.getParaList().iterator();
|
||||
while(iterator.hasNext()){
|
||||
RefTypeOrTPHOrWildcardOrGeneric typeParam = iterator.next();
|
||||
insert += new TypeToInsertString(typeParam, constraints, classConstraints).insert;
|
||||
if(iterator.hasNext())insert += ", ";
|
||||
}
|
||||
insert += ">";
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(GenericRefType genericRefType) {
|
||||
insert += genericRefType.getParsedName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(SuperWildcardType superWildcardType) {
|
||||
insert += "? super " + new TypeToInsertString(superWildcardType.getInnerType(), constraints, classConstraints).insert;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(TypePlaceholder typePlaceholder) {
|
||||
ResultPair<?, ?> resultPair = null;
|
||||
if (constraints != null)
|
||||
resultPair = constraints.getResultPairFor(typePlaceholder).orElse(null);
|
||||
if (resultPair == null)
|
||||
resultPair = classConstraints.getResultPairFor(typePlaceholder).orElse(null);
|
||||
|
||||
if (resultPair != null)
|
||||
insert += ((TypePlaceholder)resultPair.getLeft()).getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(ExtendsWildcardType extendsWildcardType) {
|
||||
insert += "? extends " + new TypeToInsertString(extendsWildcardType.getInnerType(), constraints, classConstraints).insert;
|
||||
}
|
||||
}
|
@ -1,88 +0,0 @@
|
||||
package de.dhbwstuttgart.typedeployment;
|
||||
|
||||
import de.dhbwstuttgart.syntaxtree.*;
|
||||
import de.dhbwstuttgart.syntaxtree.statement.LambdaExpression;
|
||||
import de.dhbwstuttgart.syntaxtree.type.TypePlaceholder;
|
||||
import de.dhbwstuttgart.target.generate.GenericsResult;
|
||||
import de.dhbwstuttgart.target.generate.GenericsResultSet;
|
||||
import de.dhbwstuttgart.typeinference.result.ResultPair;
|
||||
import de.dhbwstuttgart.typeinference.result.ResultSet;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class TypeInsertPlacer extends AbstractASTWalker{
|
||||
Set<TypeInsert> inserts = new HashSet<>();
|
||||
private ResultSet withResults;
|
||||
String pkgName;
|
||||
private GenericsResult genericsResult;
|
||||
|
||||
public Set<TypeInsert> getTypeInserts(SourceFile forSourceFile, ResultSet withResults, GenericsResult genericsResult){
|
||||
this.withResults = withResults;
|
||||
this.genericsResult = genericsResult;
|
||||
pkgName = forSourceFile.getPkgName();
|
||||
forSourceFile.accept(this);
|
||||
return inserts;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(ClassOrInterface classOrInterface) {
|
||||
TypeInsertPlacerClass cl = new TypeInsertPlacerClass(classOrInterface, withResults, genericsResult);
|
||||
this.inserts.addAll(cl.inserts);
|
||||
}
|
||||
}
|
||||
|
||||
class TypeInsertPlacerClass extends AbstractASTWalker{
|
||||
protected final ResultSet results;
|
||||
private GenericsResult generatedGenerics;
|
||||
protected final ClassOrInterface cl;
|
||||
public final Set<TypeInsert> inserts = new HashSet<>();
|
||||
private Method method;
|
||||
|
||||
GenericsResultSet constraints;
|
||||
GenericsResultSet classConstraints;
|
||||
|
||||
TypeInsertPlacerClass(ClassOrInterface forClass, ResultSet withResults, GenericsResult generatedGenerics){
|
||||
this.cl = forClass;
|
||||
this.method = null;
|
||||
this.results = withResults;
|
||||
this.generatedGenerics = generatedGenerics;
|
||||
forClass.accept(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(Method method) {
|
||||
this.method = method;
|
||||
constraints = generatedGenerics.get(method);
|
||||
classConstraints = generatedGenerics.get(cl);
|
||||
if(method.getReturnType() instanceof TypePlaceholder)
|
||||
inserts.add(TypeInsertFactory.createInsertPoints(
|
||||
method.getReturnType(), method.getReturnType().getOffset(), cl, method, results, constraints, classConstraints));
|
||||
super.visit(method);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(Field field) {
|
||||
if(field.getType() instanceof TypePlaceholder){
|
||||
classConstraints = generatedGenerics.get(cl);
|
||||
inserts.add(TypeInsertFactory.createInsertPoints(
|
||||
field.getType(), field.getType().getOffset(), cl, method, results, null, classConstraints));
|
||||
}
|
||||
super.visit(field);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(FormalParameter param) {
|
||||
if(param.getType() instanceof TypePlaceholder)
|
||||
inserts.add(TypeInsertFactory.createInsertPoints(
|
||||
param.getType(), param.getType().getOffset(), cl, method, results, constraints, classConstraints));
|
||||
super.visit(param);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(LambdaExpression lambdaExpression) {
|
||||
//Lambda-Ausdrücke brauchen keine Typeinsetzungen
|
||||
}
|
||||
}
|
@ -1,93 +0,0 @@
|
||||
package de.dhbwstuttgart.typedeployment;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.antlr.v4.runtime.Token;
|
||||
|
||||
public class TypeInsertPoint {
|
||||
public Token point;
|
||||
private String insertString;
|
||||
private int extraOffset = 0;
|
||||
private KindOfTypeInsertPoint kind;
|
||||
|
||||
public TypeInsertPoint(Token point, String toInsert, KindOfTypeInsertPoint kind){
|
||||
this.point = point;
|
||||
this.kind = kind;
|
||||
this.insertString = (toInsert.endsWith(" ")) ? toInsert : toInsert + " " ;
|
||||
}
|
||||
|
||||
public boolean isGenericClassInsertPoint() {
|
||||
return kind == KindOfTypeInsertPoint.GENERIC_CLASS_INSERT;
|
||||
}
|
||||
|
||||
public String insert(String intoSource, List<TypeInsertPoint> additionalOffset){
|
||||
return new StringBuilder(intoSource).insert(point.getStartIndex()+extraOffset, insertString).toString();
|
||||
}
|
||||
|
||||
public String getInsertString() {
|
||||
return insertString;
|
||||
}
|
||||
|
||||
public void addExtraOffset(int toAdd) {
|
||||
this.extraOffset += toAdd;
|
||||
}
|
||||
|
||||
public int getPositionInCode() {
|
||||
return point.getStartIndex() + extraOffset;
|
||||
}
|
||||
|
||||
/* PL 2018-06-19
|
||||
* Zwei TypeInsertPoint's sind gleich, wenn ihre point's gleich sind
|
||||
* eingefuegt damit man TypeReplaceMarker vergleichen kann
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
public boolean equals(Object obj) {
|
||||
return this == obj;
|
||||
/*
|
||||
if(!(obj instanceof TypeInsertPoint)) {
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
return
|
||||
((TypeInsertPoint)obj).getPositionInCode() == this.getPositionInCode() &&
|
||||
((TypeInsertPoint)obj).insertString.equals(this.insertString);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return getPositionInCode() * 11 * insertString.hashCode();
|
||||
}
|
||||
|
||||
public Set<TypeInsertPoint> getAdditionalPoints() {
|
||||
return this.getAdditionalPoints();
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return point.getLine() + ":" + point.getCharPositionInLine() + ":" + insertString;
|
||||
}
|
||||
|
||||
public static final class TypeInsertPointPositionComparator implements Comparator<TypeInsertPoint> {
|
||||
|
||||
@Override
|
||||
public int compare(TypeInsertPoint o1, TypeInsertPoint o2) {
|
||||
if (o1.point == null && o2.point == null) {
|
||||
return 0;
|
||||
} else if (o2.point == null) {
|
||||
return 1;
|
||||
} else if (o1.point == null) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (o1.getPositionInCode() > o2.getPositionInCode()) {
|
||||
return 1;
|
||||
} else if (o1.getPositionInCode() < o2.getPositionInCode()) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
package de.dhbwstuttgart.typeinference;
|
||||
/**
|
||||
* Operators of pairs of the unification.
|
||||
* @author Florian Steurer
|
||||
*/
|
||||
public enum PairOperator {
|
||||
/**
|
||||
* The smaller operator (T < P) is used to express a subtyping relation between
|
||||
* T and P for example in the finite closure. It is necessarily true.
|
||||
*/
|
||||
SMALLER,
|
||||
|
||||
/**
|
||||
* The smallerdot operator (T <. P) is used to express a subtyping relation between
|
||||
* of T and P in a CONSTRAINT during the unification. It is not necessarily true.
|
||||
*/
|
||||
SMALLERDOT,
|
||||
|
||||
/**
|
||||
* The smallernedot operator for arguments (T <!=. P) is the same as SMALLERDOT without
|
||||
* T == P. It is used for operations + / - / * / < / > / ... with the Supertype Number
|
||||
*/
|
||||
SMALLERNEQDOT,
|
||||
|
||||
/**
|
||||
* The smallerdot operator for arguments (T <.? P) is used to express that
|
||||
* T is an element of smArg(P) (or P is an element of grArg(T)) in a CONSTRAINT
|
||||
* during the unification. It is not necessarily true.
|
||||
*/
|
||||
SMALLERDOTWC,
|
||||
|
||||
/**
|
||||
* The equalsdot operator (T =. P) is used to express that two types during the unification
|
||||
* should be equal. It is not necessarily true.
|
||||
*/
|
||||
EQUALSDOT;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
switch (this) {
|
||||
case SMALLER: return "<";
|
||||
case SMALLERDOT: return "<.";
|
||||
case SMALLERNEQDOT: return "<!=.";
|
||||
case SMALLERDOTWC: return "<.?";
|
||||
default: return "=."; // EQUALSDOT
|
||||
}
|
||||
}
|
||||
}
|
@ -1,20 +1,9 @@
|
||||
package de.dhbwstuttgart.typeinference.assumptions;
|
||||
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Iterators;
|
||||
import de.dhbwstuttgart.bytecode.CodeGenException;
|
||||
import de.dhbwstuttgart.exceptions.DebugException;
|
||||
import de.dhbwstuttgart.syntaxtree.ClassOrInterface;
|
||||
import de.dhbwstuttgart.syntaxtree.GenericTypeVar;
|
||||
import de.dhbwstuttgart.syntaxtree.Method;
|
||||
import de.dhbwstuttgart.syntaxtree.TypeScope;
|
||||
import de.dhbwstuttgart.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
import java.util.Stack;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class TypeInferenceBlockInformation extends TypeInferenceInformation {
|
||||
private TypeScope methodContext;
|
||||
|
@ -1,8 +1,5 @@
|
||||
package de.dhbwstuttgart.typeinference.constraints;
|
||||
|
||||
import de.dhbwstuttgart.typeinference.unify.model.UnifyPair;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
|
@ -1,10 +1,5 @@
|
||||
package de.dhbwstuttgart.typeinference.constraints;
|
||||
|
||||
|
||||
import de.dhbwstuttgart.syntaxtree.type.TypePlaceholder;
|
||||
import de.dhbwstuttgart.typeinference.unify.GuavaSetOperations;
|
||||
import de.dhbwstuttgart.typeinference.unify.model.UnifyPair;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.BinaryOperator;
|
||||
import java.util.function.Consumer;
|
||||
@ -44,15 +39,6 @@ public class ConstraintSet<A> {
|
||||
//cartesianProduct().toString();
|
||||
}
|
||||
|
||||
public Set<List<Constraint<A>>> cartesianProduct(){
|
||||
Set<Constraint<A>> toAdd = new HashSet<>();
|
||||
toAdd.add(undConstraints);
|
||||
List<Set<Constraint<A>>> allConstraints = new ArrayList<>();
|
||||
allConstraints.add(toAdd);
|
||||
allConstraints.addAll(oderConstraints);
|
||||
return new GuavaSetOperations().cartesianProduct(allConstraints);
|
||||
}
|
||||
|
||||
public <B> ConstraintSet<B> map(Function<? super A, ? extends B> o) {
|
||||
Hashtable<Constraint<A>,Constraint<B>> CSA2CSB = new Hashtable<>();
|
||||
ConstraintSet<B> ret = new ConstraintSet<>();
|
||||
|
@ -7,7 +7,7 @@ import de.dhbwstuttgart.parser.NullToken;
|
||||
import de.dhbwstuttgart.parser.SourceLoc;
|
||||
import de.dhbwstuttgart.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric;
|
||||
import de.dhbwstuttgart.syntaxtree.type.TypePlaceholder;
|
||||
import de.dhbwstuttgart.typeinference.unify.model.PairOperator;
|
||||
import de.dhbwstuttgart.typeinference.PairOperator;
|
||||
import org.antlr.v4.runtime.Token;
|
||||
|
||||
|
||||
|
@ -21,6 +21,7 @@ import de.dhbwstuttgart.syntaxtree.type.RefType;
|
||||
import de.dhbwstuttgart.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric;
|
||||
import de.dhbwstuttgart.syntaxtree.type.TypePlaceholder;
|
||||
import de.dhbwstuttgart.syntaxtree.type.Void;
|
||||
import de.dhbwstuttgart.typeinference.PairOperator;
|
||||
import de.dhbwstuttgart.typeinference.assumptions.FieldAssumption;
|
||||
import de.dhbwstuttgart.typeinference.assumptions.FunNClass;
|
||||
import de.dhbwstuttgart.typeinference.assumptions.MethodAssumption;
|
||||
@ -29,7 +30,6 @@ import de.dhbwstuttgart.typeinference.constraints.Constraint;
|
||||
import de.dhbwstuttgart.typeinference.constraints.ConstraintSet;
|
||||
import de.dhbwstuttgart.typeinference.constraints.GenericsResolver;
|
||||
import de.dhbwstuttgart.typeinference.constraints.Pair;
|
||||
import de.dhbwstuttgart.typeinference.unify.model.PairOperator;
|
||||
import org.antlr.v4.runtime.Token;
|
||||
|
||||
public class TYPEStmt implements StatementVisitor {
|
||||
|
@ -1,23 +0,0 @@
|
||||
package de.dhbwstuttgart.typeinference.unify;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
import de.dhbwstuttgart.typeinference.unify.interfaces.ISetOperations;
|
||||
|
||||
/**
|
||||
* Implements set operations using google guava.
|
||||
* @author DH10STF
|
||||
*
|
||||
*/
|
||||
public class GuavaSetOperations implements ISetOperations {
|
||||
|
||||
@Override
|
||||
public <B> Set<List<B>> cartesianProduct(List<? extends Set<? extends B>> sets) {
|
||||
// Wraps the call to google guava
|
||||
return Sets.cartesianProduct(sets);
|
||||
}
|
||||
|
||||
}
|
@ -1,108 +0,0 @@
|
||||
package de.dhbwstuttgart.typeinference.unify;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import de.dhbwstuttgart.typeinference.unify.interfaces.IUnify;
|
||||
import de.dhbwstuttgart.typeinference.unify.model.PairOperator;
|
||||
import de.dhbwstuttgart.typeinference.unify.model.PlaceholderType;
|
||||
import de.dhbwstuttgart.typeinference.unify.model.TypeParams;
|
||||
import de.dhbwstuttgart.typeinference.unify.model.Unifier;
|
||||
import de.dhbwstuttgart.typeinference.unify.model.UnifyPair;
|
||||
import de.dhbwstuttgart.typeinference.unify.model.UnifyType;
|
||||
|
||||
/**
|
||||
* Implementation of the Martelli-Montanari unification algorithm.
|
||||
* @author Florian Steurer
|
||||
*/
|
||||
public class MartelliMontanariUnify implements IUnify {
|
||||
|
||||
@Override
|
||||
public Optional<Unifier> unify(Set<UnifyType> terms) {
|
||||
// Sets with less than 2 terms are trivially unified
|
||||
if(terms.size() < 2)
|
||||
return Optional.of(Unifier.identity());
|
||||
|
||||
// For the the set of terms {t1,...,tn},
|
||||
// build a list of equations {(t1 = t2), (t2 = t3), (t3 = t4), ....}
|
||||
ArrayList<UnifyPair> termsList = new ArrayList<UnifyPair>();
|
||||
Iterator<UnifyType> iter = terms.iterator();
|
||||
UnifyType prev = iter.next();
|
||||
while(iter.hasNext()) {
|
||||
UnifyType next = iter.next();
|
||||
termsList.add(new UnifyPair(prev, next, PairOperator.EQUALSDOT));
|
||||
prev = next;
|
||||
}
|
||||
|
||||
// Start with the identity unifier. Substitutions will be added later.
|
||||
Unifier mgu = Unifier.identity();
|
||||
|
||||
// Apply rules while possible
|
||||
int idx = 0;
|
||||
while(idx < termsList.size()) {
|
||||
UnifyPair pair = termsList.get(idx);
|
||||
UnifyType rhsType = pair.getRhsType();
|
||||
UnifyType lhsType = pair.getLhsType();
|
||||
TypeParams rhsTypeParams = rhsType.getTypeParams();
|
||||
TypeParams lhsTypeParams = lhsType.getTypeParams();
|
||||
|
||||
// REDUCE - Rule
|
||||
if(!(rhsType instanceof PlaceholderType) && !(lhsType instanceof PlaceholderType)) {
|
||||
Set<UnifyPair> result = new HashSet<>();
|
||||
|
||||
// f<...> = g<...> with f != g are not unifiable
|
||||
if(!rhsType.getName().equals(lhsType.getName()))
|
||||
return Optional.empty(); // conflict
|
||||
// f<t1,...,tn> = f<s1,...,sm> are not unifiable
|
||||
if(rhsTypeParams.size() != lhsTypeParams.size())
|
||||
return Optional.empty(); // conflict
|
||||
// f = g is not unifiable (cannot be f = f because erase rule would have been applied)
|
||||
//if(rhsTypeParams.size() == 0)
|
||||
//return Optional.empty();
|
||||
|
||||
// Unpack the arguments
|
||||
for(int i = 0; i < rhsTypeParams.size(); i++)
|
||||
result.add(new UnifyPair(rhsTypeParams.get(i), lhsTypeParams.get(i), PairOperator.EQUALSDOT));
|
||||
|
||||
termsList.remove(idx);
|
||||
termsList.addAll(result);
|
||||
continue;
|
||||
}
|
||||
|
||||
// DELETE - Rule
|
||||
if(pair.getRhsType().equals(pair.getLhsType())) {
|
||||
termsList.remove(idx);
|
||||
continue;
|
||||
}
|
||||
|
||||
// SWAP - Rule
|
||||
if(!(lhsType instanceof PlaceholderType) && (rhsType instanceof PlaceholderType)) {
|
||||
termsList.remove(idx);
|
||||
termsList.add(new UnifyPair(rhsType, lhsType, PairOperator.EQUALSDOT));
|
||||
continue;
|
||||
}
|
||||
|
||||
// OCCURS-CHECK
|
||||
if(pair.getLhsType() instanceof PlaceholderType
|
||||
&& pair.getRhsType().getTypeParams().occurs((PlaceholderType) pair.getLhsType()))
|
||||
return Optional.empty();
|
||||
|
||||
// SUBST - Rule
|
||||
if(lhsType instanceof PlaceholderType) {
|
||||
mgu.add((PlaceholderType) lhsType, rhsType);
|
||||
//PL 2018-04-01 nach checken, ob es richtig ist, dass keine Substitutionen uebergeben werden muessen.
|
||||
termsList = termsList.stream().map(x -> mgu.apply(x)).collect(Collectors.toCollection(ArrayList::new));
|
||||
idx = idx+1 == termsList.size() ? 0 : idx+1;
|
||||
continue;
|
||||
}
|
||||
|
||||
idx++;
|
||||
}
|
||||
|
||||
return Optional.of(mgu);
|
||||
}
|
||||
}
|
@ -1,93 +0,0 @@
|
||||
package de.dhbwstuttgart.typeinference.unify;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import de.dhbwstuttgart.typeinference.unify.interfaces.IMatch;
|
||||
import de.dhbwstuttgart.typeinference.unify.model.PairOperator;
|
||||
import de.dhbwstuttgart.typeinference.unify.model.PlaceholderType;
|
||||
import de.dhbwstuttgart.typeinference.unify.model.TypeParams;
|
||||
import de.dhbwstuttgart.typeinference.unify.model.Unifier;
|
||||
import de.dhbwstuttgart.typeinference.unify.model.UnifyPair;
|
||||
import de.dhbwstuttgart.typeinference.unify.model.UnifyType;
|
||||
|
||||
/**
|
||||
* Implementation of match derived from unification algorithm.
|
||||
* @author Martin Pluemicke
|
||||
*/
|
||||
public class Match implements IMatch {
|
||||
|
||||
@Override
|
||||
//vorne muss das Pattern stehen
|
||||
//A<X> =. A<Integer> ==> True
|
||||
//A<Integer> =. A<X> ==> False
|
||||
public Optional<Unifier> match(ArrayList<UnifyPair> termsList) {
|
||||
|
||||
// Start with the identity unifier. Substitutions will be added later.
|
||||
Unifier mgu = Unifier.identity();
|
||||
|
||||
// Apply rules while possible
|
||||
int idx = 0;
|
||||
while(idx < termsList.size()) {
|
||||
UnifyPair pair = termsList.get(idx);
|
||||
UnifyType rhsType = pair.getRhsType();
|
||||
UnifyType lhsType = pair.getLhsType();
|
||||
TypeParams rhsTypeParams = rhsType.getTypeParams();
|
||||
TypeParams lhsTypeParams = lhsType.getTypeParams();
|
||||
|
||||
// REDUCE - Rule
|
||||
if(!(rhsType instanceof PlaceholderType) && !(lhsType instanceof PlaceholderType)) {
|
||||
Set<UnifyPair> result = new HashSet<>();
|
||||
|
||||
// f<...> = g<...> with f != g are not unifiable
|
||||
if(!rhsType.getName().equals(lhsType.getName()))
|
||||
return Optional.empty(); // conflict
|
||||
// f<t1,...,tn> = f<s1,...,sm> are not unifiable
|
||||
if(rhsTypeParams.size() != lhsTypeParams.size())
|
||||
return Optional.empty(); // conflict
|
||||
// f = g is not unifiable (cannot be f = f because erase rule would have been applied)
|
||||
//if(rhsTypeParams.size() == 0)
|
||||
//return Optional.empty();
|
||||
|
||||
// Unpack the arguments
|
||||
for(int i = 0; i < rhsTypeParams.size(); i++)
|
||||
result.add(new UnifyPair(lhsTypeParams.get(i), rhsTypeParams.get(i), PairOperator.EQUALSDOT));
|
||||
|
||||
termsList.remove(idx);
|
||||
termsList.addAll(result);
|
||||
continue;
|
||||
}
|
||||
|
||||
// DELETE - Rule
|
||||
if(pair.getRhsType().equals(pair.getLhsType())) {
|
||||
termsList.remove(idx);
|
||||
continue;
|
||||
}
|
||||
|
||||
// SWAP - Rule
|
||||
if(!(lhsType instanceof PlaceholderType) && (rhsType instanceof PlaceholderType)) {
|
||||
return Optional.empty(); // conflict
|
||||
}
|
||||
|
||||
// OCCURS-CHECK
|
||||
//deleted
|
||||
|
||||
// SUBST - Rule
|
||||
if(lhsType instanceof PlaceholderType) {
|
||||
mgu.add((PlaceholderType) lhsType, rhsType);
|
||||
idx = idx+1 == termsList.size() ? 0 : idx+1;
|
||||
//PL 2024-04-08 falsch da es sich nicht um Unifikation handelt
|
||||
//termsList = termsList.stream().map(mgu::applyleft).collect(Collectors.toCollection(ArrayList::new));
|
||||
//continue;
|
||||
}
|
||||
|
||||
idx++;
|
||||
}
|
||||
|
||||
return Optional.of(mgu);
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,121 +0,0 @@
|
||||
package de.dhbwstuttgart.typeinference.unify;
|
||||
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ForkJoinPool;
|
||||
|
||||
import de.dhbwstuttgart.core.JavaTXCompiler;
|
||||
import de.dhbwstuttgart.typeinference.constraints.Constraint;
|
||||
import de.dhbwstuttgart.typeinference.constraints.ConstraintSet;
|
||||
import de.dhbwstuttgart.typeinference.constraints.Pair;
|
||||
import de.dhbwstuttgart.typeinference.unify.interfaces.IFiniteClosure;
|
||||
import de.dhbwstuttgart.typeinference.unify.model.FiniteClosure;
|
||||
import de.dhbwstuttgart.typeinference.unify.model.UnifyPair;
|
||||
|
||||
public class TypeUnify {
|
||||
|
||||
/**
|
||||
* unify parallel ohne result modell
|
||||
* @param undConstrains
|
||||
* @param oderConstraints
|
||||
* @param fc
|
||||
* @param logFile
|
||||
* @param log
|
||||
* @param cons
|
||||
* @return
|
||||
*/
|
||||
public Set<Set<UnifyPair>> unify(Set<UnifyPair> undConstrains, List<Set<Constraint<UnifyPair>>> oderConstraints, IFiniteClosure fc, Writer logFile, Boolean log, UnifyResultModel ret, UnifyTaskModel usedTasks) {
|
||||
TypeUnifyTask unifyTask = new TypeUnifyTask(undConstrains, oderConstraints, fc, true, logFile, log, 0, ret, usedTasks);
|
||||
ForkJoinPool pool = new ForkJoinPool();
|
||||
pool.invoke(unifyTask);
|
||||
Set<Set<UnifyPair>> res = unifyTask.join();
|
||||
try {
|
||||
logFile.write("\nnoShortendElements: " + unifyTask.noShortendElements + "\n");
|
||||
logFile.flush();
|
||||
}
|
||||
catch (IOException e) {
|
||||
System.err.println("no log-File");
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* unify asynchron mit Rückgabe UnifyResultModel ohne dass alle results gesammelt sind
|
||||
* @param undConstrains
|
||||
* @param oderConstraints
|
||||
* @param fc
|
||||
* @param logFile
|
||||
* @param log
|
||||
* @param cons
|
||||
* @param ret
|
||||
* @return
|
||||
*/
|
||||
public UnifyResultModel unifyAsync(Set<UnifyPair> undConstrains, List<Set<Constraint<UnifyPair>>> oderConstraints, IFiniteClosure fc, Writer logFile, Boolean log, UnifyResultModel ret, UnifyTaskModel usedTasks) {
|
||||
TypeUnifyTask unifyTask = new TypeUnifyTask(undConstrains, oderConstraints, fc, true, logFile, log, 0, ret, usedTasks);
|
||||
ForkJoinPool pool = new ForkJoinPool();
|
||||
pool.invoke(unifyTask);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* unify parallel mit Rückgabe UnifyResultModel nachdem alle results gesammelt sind
|
||||
* @param undConstrains
|
||||
* @param oderConstraints
|
||||
* @param fc
|
||||
* @param logFile
|
||||
* @param log
|
||||
* @param cons
|
||||
* @param ret
|
||||
* @return
|
||||
*/
|
||||
public UnifyResultModel unifyParallel(Set<UnifyPair> undConstrains, List<Set<Constraint<UnifyPair>>> oderConstraints, IFiniteClosure fc, Writer logFile, Boolean log, UnifyResultModel ret, UnifyTaskModel usedTasks) {
|
||||
TypeUnifyTask unifyTask = new TypeUnifyTask(undConstrains, oderConstraints, fc, true, logFile, log, 0, ret, usedTasks);
|
||||
ForkJoinPool pool = new ForkJoinPool();
|
||||
pool.invoke(unifyTask);
|
||||
Set<Set<UnifyPair>> res = unifyTask.join();
|
||||
try {
|
||||
logFile.write("\nnoShortendElements: " + unifyTask.noShortendElements +"\n");
|
||||
logFile.flush();
|
||||
}
|
||||
catch (IOException e) {
|
||||
System.err.println("no log-File");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
public Set<Set<UnifyPair>> unifySequential(Set<UnifyPair> eq, IFiniteClosure fc, FileWriter logFile, Boolean log) {
|
||||
TypeUnifyTask unifyTask = new TypeUnifyTask(eq, fc, false, logFile, log);
|
||||
Set<Set<UnifyPair>> res = unifyTask.compute();
|
||||
return res;
|
||||
}
|
||||
*/
|
||||
|
||||
/**
|
||||
* unify sequentiell mit oderconstraints
|
||||
* @param undConstrains
|
||||
* @param oderConstraints
|
||||
* @param fc
|
||||
* @param logFile
|
||||
* @param log
|
||||
* @param cons
|
||||
* @return
|
||||
*/
|
||||
public Set<Set<UnifyPair>> unifyOderConstraints(Set<UnifyPair> undConstrains, List<Set<Constraint<UnifyPair>>> oderConstraints, IFiniteClosure fc, Writer logFile, Boolean log, UnifyResultModel ret, UnifyTaskModel usedTasks) {
|
||||
TypeUnifyTask unifyTask = new TypeUnifyTask(undConstrains, oderConstraints, fc, false, logFile, log, 0, ret, usedTasks);
|
||||
Set<Set<UnifyPair>> res = unifyTask.compute();
|
||||
try {
|
||||
logFile.write("\nnoShortendElements: " + unifyTask.noShortendElements +"\n");
|
||||
logFile.flush();
|
||||
}
|
||||
catch (IOException e) {
|
||||
System.err.println("no log-File");
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
}
|
@ -1,66 +0,0 @@
|
||||
package de.dhbwstuttgart.typeinference.unify;
|
||||
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import de.dhbwstuttgart.typeinference.constraints.Constraint;
|
||||
import de.dhbwstuttgart.typeinference.constraints.ConstraintSet;
|
||||
import de.dhbwstuttgart.typeinference.constraints.Pair;
|
||||
import de.dhbwstuttgart.typeinference.unify.interfaces.IFiniteClosure;
|
||||
import de.dhbwstuttgart.typeinference.unify.model.UnifyPair;
|
||||
|
||||
public class TypeUnify2Task extends TypeUnifyTask {
|
||||
|
||||
Set<Set<UnifyPair>> setToFlatten;
|
||||
Set<UnifyPair> methodSignatureConstraintUebergabe;
|
||||
|
||||
public TypeUnify2Task(Set<Set<UnifyPair>> setToFlatten, Set<UnifyPair> eq, List<Set<Constraint<UnifyPair>>> oderConstraints, Set<UnifyPair> nextSetElement, IFiniteClosure fc, boolean parallel, Writer logFile, Boolean log, int rekTiefe, UnifyResultModel urm, UnifyTaskModel usedTasks, Set<UnifyPair> methodSignatureConstraintUebergabe) {
|
||||
super(eq, oderConstraints, fc, parallel, logFile, log, rekTiefe, urm, usedTasks);
|
||||
this.setToFlatten = setToFlatten;
|
||||
this.nextSetElement = nextSetElement;
|
||||
this.methodSignatureConstraintUebergabe = methodSignatureConstraintUebergabe;
|
||||
}
|
||||
|
||||
Set<UnifyPair> getNextSetElement() {
|
||||
return nextSetElement;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Set<Set<UnifyPair>> compute() {
|
||||
if (one) {
|
||||
System.out.println("two");
|
||||
}
|
||||
one = true;
|
||||
Set<Set<UnifyPair>> res = unify2(setToFlatten, eq, oderConstraintsField, fc, parallel, rekTiefeField, methodSignatureConstraintUebergabe);
|
||||
/*if (isUndefinedPairSetSet(res)) {
|
||||
return new HashSet<>(); }
|
||||
else
|
||||
*/
|
||||
//writeLog("xxx");
|
||||
//noOfThread--;
|
||||
synchronized (usedTasks) {
|
||||
if (this.myIsCancelled()) {
|
||||
return new HashSet<>();
|
||||
}
|
||||
else {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void closeLogFile() {
|
||||
|
||||
try {
|
||||
logFile.close();
|
||||
}
|
||||
catch (IOException ioE) {
|
||||
System.err.println("no log-File" + thNo);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,11 +0,0 @@
|
||||
package de.dhbwstuttgart.typeinference.unify;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import de.dhbwstuttgart.typeinference.unify.model.UnifyPair;
|
||||
|
||||
public interface Unifikationsalgorithmus {
|
||||
|
||||
public Set<Set<UnifyPair>> apply (Set<UnifyPair> E);
|
||||
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
package de.dhbwstuttgart.typeinference.unify;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import de.dhbwstuttgart.typeinference.result.ResultSet;
|
||||
|
||||
public class UnifyResultEvent {
|
||||
|
||||
private List<ResultSet> newTypeResult;
|
||||
|
||||
public UnifyResultEvent(List<ResultSet> newTypeResult) {
|
||||
this.newTypeResult = newTypeResult;
|
||||
}
|
||||
|
||||
public List<ResultSet> getNewTypeResult() {
|
||||
return newTypeResult;
|
||||
}
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
package de.dhbwstuttgart.typeinference.unify;
|
||||
|
||||
public interface UnifyResultListener {
|
||||
|
||||
void onNewTypeResultFound(UnifyResultEvent evt);
|
||||
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
package de.dhbwstuttgart.typeinference.unify;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import de.dhbwstuttgart.typeinference.result.ResultSet;
|
||||
import de.dhbwstuttgart.typeinference.unify.model.UnifyPair;
|
||||
|
||||
public class UnifyResultListenerImpl implements UnifyResultListener {
|
||||
|
||||
List<ResultSet> results = new ArrayList<>();
|
||||
|
||||
public synchronized void onNewTypeResultFound(UnifyResultEvent evt) {
|
||||
results.addAll(evt.getNewTypeResult());
|
||||
}
|
||||
|
||||
public List<ResultSet> getResults() {
|
||||
return results;
|
||||
}
|
||||
|
||||
}
|
@ -1,59 +0,0 @@
|
||||
package de.dhbwstuttgart.typeinference.unify;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import de.dhbwstuttgart.syntaxtree.factory.UnifyTypeFactory;
|
||||
import de.dhbwstuttgart.typeinference.constraints.ConstraintSet;
|
||||
import de.dhbwstuttgart.typeinference.result.ResultSet;
|
||||
import de.dhbwstuttgart.typeinference.unify.interfaces.IFiniteClosure;
|
||||
import de.dhbwstuttgart.typeinference.unify.model.PairOperator;
|
||||
import de.dhbwstuttgart.typeinference.unify.model.UnifyPair;
|
||||
|
||||
public class UnifyResultModel {
|
||||
|
||||
ConstraintSet<de.dhbwstuttgart.typeinference.constraints.Pair> cons;
|
||||
|
||||
IFiniteClosure fc;
|
||||
|
||||
public UnifyResultModel(ConstraintSet<de.dhbwstuttgart.typeinference.constraints.Pair> cons,
|
||||
IFiniteClosure fc) {
|
||||
this.cons = cons;
|
||||
this.fc = fc;
|
||||
}
|
||||
|
||||
private List<UnifyResultListener> listeners = new ArrayList<>();
|
||||
|
||||
public void addUnifyResultListener(UnifyResultListener listenerToAdd) {
|
||||
listeners.add(listenerToAdd);
|
||||
}
|
||||
|
||||
public void removeUnifyResultListener(UnifyResultListener listenerToRemove) {
|
||||
listeners.remove(listenerToRemove);
|
||||
}
|
||||
|
||||
public void notify(Set<Set<UnifyPair>> eqPrimePrimeSet) {
|
||||
Set<Set<UnifyPair>> eqPrimePrimeSetRet = eqPrimePrimeSet.stream().map(x -> {
|
||||
Optional<Set<UnifyPair>> res = new RuleSet().subst(x.stream().map(y -> {
|
||||
if (y.getPairOp() == PairOperator.SMALLERDOTWC) y.setPairOp(PairOperator.EQUALSDOT);
|
||||
return y; //alle Paare a <.? b erden durch a =. b ersetzt
|
||||
}).collect(Collectors.toCollection(HashSet::new)));
|
||||
if (res.isPresent()) {//wenn subst ein Erg liefert wurde was veraendert
|
||||
return new TypeUnifyTask().applyTypeUnificationRules(res.get(), fc);
|
||||
}
|
||||
else return x; //wenn nichts veraendert wurde wird x zurueckgegeben
|
||||
}).collect(Collectors.toCollection(HashSet::new));
|
||||
List<ResultSet> newResult = eqPrimePrimeSetRet.stream().map(unifyPairs ->
|
||||
new ResultSet(UnifyTypeFactory.convert(unifyPairs, de.dhbwstuttgart.typeinference.constraints.Pair.generateTPHMap(cons))))
|
||||
.collect(Collectors.toList());
|
||||
UnifyResultEvent evt = new UnifyResultEvent(newResult);
|
||||
|
||||
for (UnifyResultListener listener : listeners) {
|
||||
listener.onNewTypeResultFound(evt);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
package de.dhbwstuttgart.typeinference.unify;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class UnifyTaskModel {
|
||||
|
||||
ArrayList<TypeUnifyTask> usedTasks = new ArrayList<>();
|
||||
|
||||
public synchronized void add(TypeUnifyTask t) {
|
||||
usedTasks.add(t);
|
||||
}
|
||||
|
||||
public synchronized void cancel() {
|
||||
for(TypeUnifyTask t : usedTasks) {
|
||||
t.myCancel(true);
|
||||
}
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user