Anpassung zur Integration von Functional Interfaces und FunN$$-Typen

modified:   src/main/java/de/dhbwstuttgart/parser/SyntaxTreeGenerator/FCGenerator.java
	modified:   src/main/java/de/dhbwstuttgart/parser/SyntaxTreeGenerator/SyntaxTreeGenerator.java
	modified:   src/main/java/de/dhbwstuttgart/syntaxtree/ClassOrInterface.java
	modified:   src/main/java/de/dhbwstuttgart/syntaxtree/Record.java
	modified:   src/main/java/de/dhbwstuttgart/syntaxtree/factory/ASTFactory.java
	modified:   src/main/java/de/dhbwstuttgart/typeinference/assumptions/FunNClass.java
	modified:   src/main/java/de/dhbwstuttgart/typeinference/unify/RuleSet.java
	modified:   src/main/java/de/dhbwstuttgart/typeinference/unify/interfaces/IFiniteClosure.java
	modified:   src/main/java/de/dhbwstuttgart/typeinference/unify/model/FiniteClosure.java
	modified:   src/test/java/targetast/ASTToTypedTargetAST.java
This commit is contained in:
pl@gohorb.ba-horb.de 2023-10-27 21:17:52 +02:00
parent df852ef36e
commit c4ce97f20c
10 changed files with 64 additions and 30 deletions

View File

@ -34,11 +34,12 @@ public class FCGenerator {
//PL 2018-09-18: gtvs vor die for-Schleife gezogen, damit immer die gleichen Typeplaceholder eingesetzt werden.
HashMap<String, RefTypeOrTPHOrWildcardOrGeneric> gtvs = new HashMap<>();
for(ClassOrInterface cly : availableClasses){
pairs.addAll(getSuperTypes(cly, availableClasses, gtvs, classLoader));
List<Pair> newPairs = getSuperTypes(cly, availableClasses, gtvs, classLoader);
pairs.addAll(newPairs);
//For all Functional Interfaces FI: FunN$$<... args auf dem Functional Interface ...> <. FI is added to FC
if (isFunctionalInterface(cly)) {
pairs.add(genImplFunType(cly));
pairs.add(genImplFunType(cly, newPairs.get(0).TA1, gtvs));
}
}
return pairs;
@ -46,17 +47,22 @@ public class FCGenerator {
private static Boolean isFunctionalInterface(ClassOrInterface cly) {
return (cly.isInterface() && cly.getMethods().size() == 1);
return (cly.isInterface() && (cly.isFunctionalInterface() || cly.getMethods().size() == 1));
}
private static Pair genImplFunType(ClassOrInterface cly) {
Method m = cly.getMethods().get(0);
List<RefTypeOrTPHOrWildcardOrGeneric> tl =
(m.getParameterList().getFormalparalist().stream().map(p -> p.getType()).collect(Collectors.toList()));
tl.add(m.getReturnType());
return new Pair(new RefType(new JavaClassName("Fun" + (tl.size()-1) + "$$"), tl, new NullToken()),
new RefType(cly.getClassName(), new NullToken()));
// new FunN(lambdaParams),
private static Pair genImplFunType(ClassOrInterface cly, RefTypeOrTPHOrWildcardOrGeneric fIType, HashMap<String, RefTypeOrTPHOrWildcardOrGeneric> gtvs) {
for(Method m : cly.getMethods()) {
if (!java.lang.reflect.Modifier.isAbstract(m.modifier))
continue;
List<RefTypeOrTPHOrWildcardOrGeneric> tl =
(m.getParameterList().getFormalparalist()
.stream().map(p -> p.getType().acceptTV(new TypeExchanger(gtvs)))
.collect(Collectors.toList()));
tl.add(m.getReturnType().acceptTV(new TypeExchanger(gtvs)));
return new Pair(new RefType(new JavaClassName("Fun" + (tl.size()-1) + "$$"), tl, new NullToken()),
fIType);
}
return null; //kann nicht passieren, da die Methode nur aufgerufen wird wenn cl Functional Interface ist
}

View File

@ -210,6 +210,7 @@ public class SyntaxTreeGenerator {
List<Method> methods = new ArrayList<>();
List<Constructor> constructors = new ArrayList<>();
Boolean isInterface = false;
Boolean isFunctionalInterface = false;
List<RefType> implementedInterfaces = new ArrayList<>();
List<RefType> permittedSubtypes = new ArrayList<>();
for (ClassBodyDeclarationContext clsbodydecl : ctx.classBody().classBodyDeclaration()) {
@ -233,7 +234,7 @@ public class SyntaxTreeGenerator {
}
var ctor = Optional.of(this.generatePseudoConstructor(ctx.identifier().getText(), fieldInitializations, genericClassParameters, offset));
var staticCtor = Optional.of(this.generateStaticConstructor(ctx.identifier().getText(), staticFieldInitializations, genericClassParameters, offset));
return new ClassOrInterface(modifiers, name, fielddecl, ctor, staticCtor, methods, constructors, genericClassParameters, superClass, isInterface, implementedInterfaces, permittedSubtypes, offset);
return new ClassOrInterface(modifiers, name, fielddecl, ctor, staticCtor, methods, constructors, genericClassParameters, superClass, isInterface, isFunctionalInterface, implementedInterfaces, permittedSubtypes, offset);
}
@ -408,7 +409,7 @@ public class SyntaxTreeGenerator {
}
var staticCtor = Optional.of(this.generateStaticConstructor(ctx.identifier().getText(), staticFieldInitializations, genericParams, ctx.getStart()));
return new ClassOrInterface(modifiers, name, fields, Optional.empty(), staticCtor, methods, new ArrayList<>(), genericParams, superClass, true, extendedInterfaces, permittedSubtypes, ctx.getStart());
return new ClassOrInterface(modifiers, name, fields, Optional.empty(), staticCtor, methods, new ArrayList<>(), genericParams, superClass, true, methods.size() == 1 ? true : false, extendedInterfaces, permittedSubtypes, ctx.getStart());
}
private GenericDeclarationList createEmptyGenericDeclarationList(Token classNameIdentifier) {

View File

@ -28,11 +28,12 @@ public class ClassOrInterface extends SyntaxTreeNode implements TypeScope {
private GenericDeclarationList genericClassParameters;
private RefType superClass;
protected boolean isInterface;
protected boolean isFunctionalInterface;
private List<RefType> implementedInterfaces;
private List<RefType> permittedSubtypes;
private List<Constructor> constructors;
public ClassOrInterface(int modifiers, JavaClassName name, List<Field> fielddecl, Optional<Constructor> fieldInitializations, Optional<Method> staticInitializer, List<Method> methods, List<Constructor> constructors, GenericDeclarationList genericClassParameters, RefType superClass, Boolean isInterface, List<RefType> implementedInterfaces, List<RefType> permittedSubtypes, Token offset) {
public ClassOrInterface(int modifiers, JavaClassName name, List<Field> fielddecl, Optional<Constructor> fieldInitializations, Optional<Method> staticInitializer, List<Method> methods, List<Constructor> constructors, GenericDeclarationList genericClassParameters, RefType superClass, Boolean isInterface, Boolean isFunctionalInterface, List<RefType> implementedInterfaces, List<RefType> permittedSubtypes, Token offset) {
super(offset);
if (isInterface) {
modifiers |= Modifier.INTERFACE | Modifier.ABSTRACT;
@ -45,6 +46,7 @@ public class ClassOrInterface extends SyntaxTreeNode implements TypeScope {
this.genericClassParameters = genericClassParameters;
this.superClass = superClass;
this.isInterface = isInterface;
this.isFunctionalInterface= isFunctionalInterface;
this.implementedInterfaces = implementedInterfaces;
this.permittedSubtypes = permittedSubtypes;
this.methods = methods;
@ -64,6 +66,7 @@ public class ClassOrInterface extends SyntaxTreeNode implements TypeScope {
this.genericClassParameters = cl.genericClassParameters;
this.superClass = cl.superClass;
this.isInterface = cl.isInterface;
this.isFunctionalInterface= cl.isFunctionalInterface;
this.implementedInterfaces = cl.implementedInterfaces;
this.methods = new ArrayList<>(cl.methods);
this.constructors = new ArrayList<>(cl.constructors);
@ -82,6 +85,10 @@ public class ClassOrInterface extends SyntaxTreeNode implements TypeScope {
return (Modifier.INTERFACE & this.getModifiers()) != 0;
}
public boolean isFunctionalInterface() {
return this.isFunctionalInterface;
}
// Gets if it is added
public Boolean areMethodsAdded() {
return methodAdded;
@ -173,4 +180,5 @@ public class ClassOrInterface extends SyntaxTreeNode implements TypeScope {
public String toString() {
return this.name.toString() + this.genericClassParameters.toString();
}
}

View File

@ -14,6 +14,6 @@ import javax.swing.text.html.Option;
public class Record extends ClassOrInterface {
public Record(int modifiers, JavaClassName name, List<Field> fielddecl, Optional<Constructor> fieldInitializations, Optional<Method> staticInitializer, List<Method> methods, List<Constructor> constructors, GenericDeclarationList genericClassParameters, RefType superClass, Boolean isInterface, List<RefType> implementedInterfaces, Token offset) {
super(modifiers, name, fielddecl, fieldInitializations, staticInitializer, methods, constructors, genericClassParameters, superClass, isInterface, implementedInterfaces, new ArrayList<>(), offset);
super(modifiers, name, fielddecl, fieldInitializations, staticInitializer, methods, constructors, genericClassParameters, superClass, isInterface, methods.size() == 1 ? true : false, implementedInterfaces, new ArrayList<>(), offset);
}
}

View File

@ -1,6 +1,7 @@
package de.dhbwstuttgart.syntaxtree.factory;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.Type;
@ -86,7 +87,6 @@ public class ASTFactory {
} catch (IOException e) {
// Skip
}
JavaClassName name = new JavaClassName(jreClass.getName());
List<Method> methoden = new ArrayList<>();
List<de.dhbwstuttgart.syntaxtree.Constructor> konstruktoren = new ArrayList<>();
@ -112,6 +112,12 @@ public class ASTFactory {
}
int modifier = jreClass.getModifiers();
boolean isInterface = jreClass.isInterface();
List<Annotation> aLA;
boolean isFunctionalInterface =
(aLA = Arrays.asList(jreClass.getAnnotations())).size() > 0 &&
aLA.get(0) instanceof FunctionalInterface ?
true :
false;
// see: https://stackoverflow.com/questions/9934774/getting-generic-parameter-from-supertype-class
ParameterizedType parameterSuperClass = null;
Type tempSuperClass = jreClass.getGenericSuperclass();
@ -141,7 +147,7 @@ public class ASTFactory {
Token offset = new NullToken(); // Braucht keinen Offset, da diese Klasse nicht aus einem Quellcode geparst wurde
var cinf = new ClassOrInterface(modifier, name, felder, Optional.empty() /* eingefuegt PL 2018-11-24 */, Optional.empty(), methoden, konstruktoren, genericDeclarationList, superClass, isInterface, implementedInterfaces, permittedSubtypes, offset);
var cinf = new ClassOrInterface(modifier, name, felder, Optional.empty() /* eingefuegt PL 2018-11-24 */, Optional.empty(), methoden, konstruktoren, genericDeclarationList, superClass, isInterface, isFunctionalInterface, implementedInterfaces, permittedSubtypes, offset);
cache.put(jreClass, cinf);
return cinf;
}

View File

@ -22,7 +22,7 @@ import java.util.Optional;
public class FunNClass extends ClassOrInterface {
public FunNClass(List<GenericRefType> funNParams) {
super(0, new JavaClassName("Fun" + (funNParams.size() - 1)), new ArrayList<>(), Optional.empty(), Optional.empty() /* eingefuegt PL 2018-11-24 */, createMethods(funNParams), new ArrayList<>(), createGenerics(funNParams), ASTFactory.createObjectType(), true, new ArrayList<>(), new ArrayList<>(), new NullToken());
super(0, new JavaClassName("Fun" + (funNParams.size() - 1)), new ArrayList<>(), Optional.empty(), Optional.empty() /* eingefuegt PL 2018-11-24 */, createMethods(funNParams), new ArrayList<>(), createGenerics(funNParams), ASTFactory.createObjectType(), true, false, new ArrayList<>(), new ArrayList<>(), new NullToken());
}

View File

@ -890,26 +890,39 @@ public class RuleSet implements IRuleSet{
if(!(lhsType instanceof FunNType))
return Optional.empty();
//FunN$$<...> <. FunctinalInterface wird umgewandelt in FunN$$<...> <. FunN$$<... args aus FuntionalInterface ...>
//FunN$$<...> <. FunctinalInterface<...> wird umgewandelt in FunN$$<...> <. FunN$$<... args aus FuntionalInterface ...>
if (rhsType instanceof ReferenceType) {
UnifyType typeD = pair.getRhsType();
UnifyType typeFI = pair.getRhsType();
Optional<UnifyType> opt = fc.getRightHandedNoParameterType(typeD.getName());
Optional<UnifyType> opt = fc.getRightHandedFunctionalInterfaceType(typeFI.getName());
if(!opt.isPresent())
return Optional.empty();
// Should be eual as typeD
UnifyType typeFunFc = opt.get();
// The generic Version of typeFI (FI<a1, a2, a3, ... >)
UnifyType typeDgen = opt.get();
// Actually greater+ because the types are ensured to have different names
Set<UnifyType> smaller = fc.getChildren(typeDgen);
opt = smaller.stream().filter(x -> x.getName().equals(pair.getLhsType().getName())).findAny();
if(!(typeFunFc instanceof FunNType))
if(!opt.isPresent())
return Optional.empty();
TypeParams typeDParams = typeFI.getTypeParams();
TypeParams typeDgenParams = typeDgen.getTypeParams();
Unifier unif = Unifier.identity();
for(int i = 0; i < typeDParams.size(); i++) {
if (typeDgenParams.get(i) instanceof PlaceholderType)
unif.add((PlaceholderType) typeDgenParams.get(i), typeDParams.get(i));
else System.out.println("ERROR");
}
UnifyType newRhsType = opt.get();
Set<UnifyPair> result = new HashSet<>();
result.add(new UnifyPair(lhsType, newRhsType, PairOperator.SMALLERDOT, pair.getSubstitution(), pair.getBasePair()));
result.add(new UnifyPair(lhsType, unif.apply(newRhsType), PairOperator.SMALLERDOT, pair.getSubstitution(), pair.getBasePair()));
return Optional.of(result);
}

View File

@ -60,7 +60,7 @@ public interface IFiniteClosure {
public Set<UnifyType> smArg(FunNType type, Set<UnifyType> fBounded);
public Optional<UnifyType> getLeftHandedType(String typeName);
public Optional<UnifyType> getRightHandedNoParameterType(String typeName);
public Optional<UnifyType> getRightHandedFunctionalInterfaceType(String typeName);
public Set<UnifyType> getAncestors(UnifyType t);
public Set<UnifyType> getChildren(UnifyType t);
public Set<UnifyType> getAllTypesByName(String typeName);

View File

@ -609,13 +609,13 @@ implements IFiniteClosure {
}
@Override
public Optional<UnifyType> getRightHandedNoParameterType(String typeName) {
public Optional<UnifyType> getRightHandedFunctionalInterfaceType(String typeName) {
if(!strInheritanceGraph.containsKey(typeName))
return Optional.empty();
for(UnifyPair pair : pairs)
if(pair.getRhsType().getName().equals(typeName) && pair.getRhsType().typeParams.size() == 0)
return Optional.of(pair.getLhsType());
if(pair.getRhsType().getName().equals(typeName))
return Optional.of(pair.getRhsType());
return Optional.empty();
}

View File

@ -22,7 +22,7 @@ public class ASTToTypedTargetAST {
@Test
public void emptyClass() {
ClassOrInterface emptyClass = new ClassOrInterface(0, new JavaClassName("EmptyClass"), new ArrayList<>(), Optional.empty(), Optional.empty(), new ArrayList<>(), new ArrayList<>(), new GenericDeclarationList(new ArrayList<>(), new NullToken()), new RefType(new JavaClassName("Object"), new NullToken()), false, new ArrayList<>(), new ArrayList<>(), new NullToken());
ClassOrInterface emptyClass = new ClassOrInterface(0, new JavaClassName("EmptyClass"), new ArrayList<>(), Optional.empty(), Optional.empty(), new ArrayList<>(), new ArrayList<>(), new GenericDeclarationList(new ArrayList<>(), new NullToken()), new RefType(new JavaClassName("Object"), new NullToken()), false, false, new ArrayList<>(), new ArrayList<>(), new NullToken());
ResultSet emptyResultSet = new ResultSet(new HashSet<>());
TargetStructure emptyTargetClass = new ASTToTargetAST(List.of(emptyResultSet)).convert(emptyClass);
assert emptyTargetClass.getName().equals("EmptyClass");