forked from JavaTX/JavaCompilerCore
Merge branch 'bytecode2' of ssh://gohorb.ba-horb.de/bahome/projekt/git/JavaCompilerCore into unify-test
modified: ../../src/de/dhbwstuttgart/bytecode/BytecodeGen.java modified: ../../src/de/dhbwstuttgart/bytecode/BytecodeGenMethod.java new file: ../../src/de/dhbwstuttgart/bytecode/constraint/EqualConstraint.java new file: ../../src/de/dhbwstuttgart/bytecode/constraint/ExtendsConstraint.java new file: ../../src/de/dhbwstuttgart/bytecode/constraint/TPHConstraint.java modified: ../../src/de/dhbwstuttgart/parser/SyntaxTreeGenerator/StatementGenerator.java modified: ../../src/de/dhbwstuttgart/parser/SyntaxTreeGenerator/SyntaxTreeGenerator.java modified: ../../src/de/dhbwstuttgart/typeinference/typeAlgo/TYPEStmt.java modified: ../../src/de/dhbwstuttgart/typeinference/unify/RuleSet.java new file: ../bytecode/FieldTest.java modified: ../bytecode/MatrixOpTest.java modified: ../bytecode/OverloadingSortingTest.java new file: ../bytecode/YTest.java new file: ../bytecode/javFiles/Field.jav modified: ../bytecode/javFiles/Matrix.jav modified: ../bytecode/javFiles/Sorting.jav modified: ../bytecode/javFiles/Tph.jav new file: ../bytecode/javFiles/Y.jav
This commit is contained in:
commit
d5d49ad30e
@ -2,7 +2,9 @@ package de.dhbwstuttgart.bytecode;
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import de.dhbwstuttgart.exceptions.NotImplementedException;
|
import de.dhbwstuttgart.exceptions.NotImplementedException;
|
||||||
@ -13,6 +15,9 @@ import org.objectweb.asm.MethodVisitor;
|
|||||||
import org.objectweb.asm.Opcodes;
|
import org.objectweb.asm.Opcodes;
|
||||||
import org.objectweb.asm.Type;
|
import org.objectweb.asm.Type;
|
||||||
|
|
||||||
|
import de.dhbwstuttgart.bytecode.constraint.ExtendsConstraint;
|
||||||
|
import de.dhbwstuttgart.bytecode.constraint.TPHConstraint;
|
||||||
|
import de.dhbwstuttgart.bytecode.constraint.TPHConstraint.Relation;
|
||||||
import de.dhbwstuttgart.bytecode.descriptor.DescriptorToString;
|
import de.dhbwstuttgart.bytecode.descriptor.DescriptorToString;
|
||||||
import de.dhbwstuttgart.bytecode.descriptor.TypeToDescriptor;
|
import de.dhbwstuttgart.bytecode.descriptor.TypeToDescriptor;
|
||||||
import de.dhbwstuttgart.bytecode.signature.Signature;
|
import de.dhbwstuttgart.bytecode.signature.Signature;
|
||||||
@ -175,8 +180,28 @@ public class BytecodeGen implements ASTVisitor {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(Constructor field) {
|
public void visit(Constructor field) {
|
||||||
|
System.out.println("ResultSet: ");
|
||||||
|
resultSet.results.forEach(a->{
|
||||||
|
System.out.println(a.getLeft().toString() + " = " + a.getRight().toString());
|
||||||
|
});
|
||||||
|
System.out.println("---------------");
|
||||||
field.getParameterList().accept(this);
|
field.getParameterList().accept(this);
|
||||||
|
|
||||||
|
String methParamTypes = field.name+"%%";
|
||||||
|
|
||||||
|
Iterator<FormalParameter> itr = field.getParameterList().iterator();
|
||||||
|
while(itr.hasNext()) {
|
||||||
|
FormalParameter fp = itr.next();
|
||||||
|
methParamTypes += resultSet.resolveType(fp.getType()).resolvedType.acceptTV(new TypeToDescriptor())+";";
|
||||||
|
// methParamTypes += resultSet.resolveType(fp.getType()).resolvedType.acceptTV(new TypeToSignature())+";";
|
||||||
|
}
|
||||||
|
|
||||||
|
if(methodNameAndParamsT.contains(methParamTypes)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
methodNameAndParamsT.add(methParamTypes);
|
||||||
|
System.out.println("Method: "+field.name +" , paramsType: "+methParamTypes);
|
||||||
|
|
||||||
String desc = null;
|
String desc = null;
|
||||||
boolean hasGen = false;
|
boolean hasGen = false;
|
||||||
|
|
||||||
@ -190,7 +215,7 @@ public class BytecodeGen implements ASTVisitor {
|
|||||||
}
|
}
|
||||||
String sig = null;
|
String sig = null;
|
||||||
if(hasGen) {
|
if(hasGen) {
|
||||||
ArrayList<GenericInsertPair> pairs = simplifyPairs(field.name,tphExtractor.allPairs);
|
ArrayList<GenericInsertPair> pairs = simplifyPairs(field.name,tphExtractor.allPairs, tphExtractor.allCons);
|
||||||
Signature signature = new Signature(field, genericsAndBounds,methodParamsAndTypes,resultSet,pairs);
|
Signature signature = new Signature(field, genericsAndBounds,methodParamsAndTypes,resultSet,pairs);
|
||||||
sig = signature.toString();
|
sig = signature.toString();
|
||||||
}
|
}
|
||||||
@ -259,7 +284,11 @@ public class BytecodeGen implements ASTVisitor {
|
|||||||
/* if method has generics or return type is TPH, create signature */
|
/* if method has generics or return type is TPH, create signature */
|
||||||
// zwite operand muss weggelassen werden
|
// zwite operand muss weggelassen werden
|
||||||
if(hasGen||resultSet.resolveType(method.getReturnType()).resolvedType.acceptTV(new TypeToString()).equals("TPH")) {
|
if(hasGen||resultSet.resolveType(method.getReturnType()).resolvedType.acceptTV(new TypeToString()).equals("TPH")) {
|
||||||
ArrayList<GenericInsertPair> pairs = simplifyPairs(method.name,tphExtractor.allPairs);
|
System.out.println("ALL CONST: " + tphExtractor.allCons.size());
|
||||||
|
tphExtractor.allCons.forEach(c->System.out.println(c.toString()));
|
||||||
|
System.out.println("----------------");
|
||||||
|
HashMap<TPHConstraint, HashSet<String>> constraints = simplifyPairs(method.name,tphExtractor.allCons);
|
||||||
|
ArrayList<GenericInsertPair> pairs = simplifyPairs(method.name,tphExtractor.allPairs,tphExtractor.allCons);
|
||||||
System.out.println(method.name + " => Simplified Pairs: ");
|
System.out.println(method.name + " => Simplified Pairs: ");
|
||||||
pairs.forEach(p->System.out.println(p.TA1.getName() + " -> "+p.TA2.getName()));
|
pairs.forEach(p->System.out.println(p.TA1.getName() + " -> "+p.TA2.getName()));
|
||||||
Signature signature = new Signature(method, genericsAndBoundsMethod, genericsAndBounds,methodParamsAndTypes,resultSet, pairs);
|
Signature signature = new Signature(method, genericsAndBoundsMethod, genericsAndBounds,methodParamsAndTypes,resultSet, pairs);
|
||||||
@ -280,9 +309,263 @@ public class BytecodeGen implements ASTVisitor {
|
|||||||
mv.visitEnd();
|
mv.visitEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
private ArrayList<GenericInsertPair> simplifyPairs(String methodName, ArrayList<GenericInsertPair> allPairs) {
|
private HashMap<TPHConstraint, HashSet<String>> simplifyPairs(String name, ArrayList<TPHConstraint> allCons) {
|
||||||
|
// 1. check if there are any cycles like L<R and R<L:
|
||||||
|
// a) yes => set L=R and:
|
||||||
|
// * remove both constraints
|
||||||
|
// * substitute L with R in all constraint
|
||||||
|
// b)no => go to next step
|
||||||
|
// 2. check the result of step 1 if there are any equal-constraints like L=R, M=R ..
|
||||||
|
// a) yes => put all such TPhs in a map and define "key-Cons"
|
||||||
|
// -- key-Cons = TPH < Object --
|
||||||
|
// put this Constraint and the
|
||||||
|
// b) no
|
||||||
|
// 3. is
|
||||||
|
ArrayList<TPHConstraint> consToRemove = new ArrayList<>();
|
||||||
|
// step 1:
|
||||||
|
for(TPHConstraint c : allCons) {
|
||||||
|
|
||||||
|
String left = c.getLeft();
|
||||||
|
String right = c.getRight();
|
||||||
|
if(c.getRel() == Relation.EXTENDS) {
|
||||||
|
TPHConstraint revCon = getReverseConstraint(allCons,left,right);
|
||||||
|
if(revCon != null) {
|
||||||
|
revCon.setRel(Relation.EQUAL);
|
||||||
|
consToRemove.add(revCon);
|
||||||
|
c.setRel(Relation.EQUAL);
|
||||||
|
substituteTPH(allCons,left, right);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
System.out.println();
|
||||||
|
System.out.println("NEW ALL CONST: " + allCons.size());
|
||||||
|
allCons.forEach(c->System.out.println(c.toString()));
|
||||||
|
System.out.println("----------------");
|
||||||
|
allCons.removeAll(consToRemove);
|
||||||
|
consToRemove = new ArrayList<>();
|
||||||
|
|
||||||
|
int size = allCons.size();
|
||||||
|
|
||||||
|
System.out.println("AFTER DELETE ALL CONST: " + allCons.size());
|
||||||
|
allCons.forEach(c->System.out.println(c.toString()));
|
||||||
|
System.out.println("----------------");
|
||||||
|
HashMap<TPHConstraint, HashSet<String>> result = new HashMap<>();
|
||||||
|
|
||||||
|
for(TPHConstraint c : allCons) {
|
||||||
|
if(c.getRel()==Relation.EQUAL) {
|
||||||
|
HashSet<String> equalTPHs = getEqualsTPHs(result, c);
|
||||||
|
TPHConstraint constraint = getKeyConstraint(result,c);
|
||||||
|
equalTPHs.add(c.getLeft());
|
||||||
|
equalTPHs.add(c.getRight());
|
||||||
|
result.put(constraint, equalTPHs);
|
||||||
|
consToRemove.add(c);
|
||||||
|
size--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
System.out.println("Step 2 Result: ");
|
||||||
|
result.forEach((c,hs)->{
|
||||||
|
System.out.print(c.toString() + " -> ");
|
||||||
|
hs.forEach(s->{
|
||||||
|
System.out.print(s + ", ");
|
||||||
|
});
|
||||||
|
System.out.println();
|
||||||
|
});
|
||||||
|
System.out.println("----------------");
|
||||||
|
allCons.removeAll(consToRemove);
|
||||||
|
allCons.addAll(result.keySet());
|
||||||
|
|
||||||
|
if(!allCons.isEmpty() && allCons.size()<2) {
|
||||||
|
|
||||||
|
if(!result.containsKey(allCons.get(0)))
|
||||||
|
result.put(allCons.get(0), null);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
size += result.keySet().size();
|
||||||
|
|
||||||
|
for(TPHConstraint c : allCons) {
|
||||||
|
if(c.getRight().equals(Type.getInternalName(Object.class)))
|
||||||
|
size--;
|
||||||
|
}
|
||||||
|
|
||||||
|
ArrayList<TypePlaceholder> methodTphs = new ArrayList<>();
|
||||||
|
for(MethodAndTPH m : tphExtractor.ListOfMethodsAndTph) {
|
||||||
|
if(m.getName().equals(name)) {
|
||||||
|
methodTphs = m.getTphs();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
HashMap<String, String> subAndSuper = new HashMap<>();
|
||||||
|
for(TPHConstraint c : allCons) {
|
||||||
|
if(subAndSuper.containsKey(c.getLeft())) {
|
||||||
|
LinkedList<String> all = new LinkedList<>();
|
||||||
|
all.add(c.getLeft());
|
||||||
|
String sup =c.getRight();
|
||||||
|
all.add(sup);
|
||||||
|
HashMap<String, String> ss = new HashMap<>();
|
||||||
|
for(TPHConstraint constr : allCons) {
|
||||||
|
ss.put(constr.getLeft(), constr.getRight());
|
||||||
|
}
|
||||||
|
while(ss.containsKey(sup)) {
|
||||||
|
sup = ss.get(sup);
|
||||||
|
all.add(sup);
|
||||||
|
}
|
||||||
|
if(!containTPH(methodTphs, all.getLast()))
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
subAndSuper.put(c.getLeft(), c.getRight());
|
||||||
|
}
|
||||||
|
|
||||||
|
int numOfVisitedPairs = 0;
|
||||||
|
for(String sub : subAndSuper.keySet()) {
|
||||||
|
if(isTPHInConstraint(result,sub))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if(!containTPH(methodTphs,sub))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if(numOfVisitedPairs>=size)
|
||||||
|
break;
|
||||||
|
LinkedList<String> tphInRel = new LinkedList<>();
|
||||||
|
tphInRel.add(sub);
|
||||||
|
String superT = subAndSuper.get(sub);
|
||||||
|
tphInRel.add(superT);
|
||||||
|
|
||||||
|
numOfVisitedPairs++;
|
||||||
|
boolean isCycle = false;
|
||||||
|
while(subAndSuper.containsKey(superT)) {
|
||||||
|
superT = subAndSuper.get(superT);
|
||||||
|
if(tphInRel.contains(superT)) {
|
||||||
|
isCycle = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
tphInRel.add(superT);
|
||||||
|
numOfVisitedPairs++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Subtype
|
||||||
|
String subTphRes = tphInRel.getFirst();
|
||||||
|
// Die größte Supertype
|
||||||
|
String superTphRes = tphInRel.getLast();
|
||||||
|
|
||||||
|
while(subAndSuper.containsValue(subTphRes)) {
|
||||||
|
for(String tph : subAndSuper.keySet()) {
|
||||||
|
if(containTPH(methodTphs,tph) && subAndSuper.get(tph).equals(subTphRes)) {
|
||||||
|
subTphRes = tph;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(subTphRes.equals(tphInRel.getFirst())) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
tphInRel.addFirst(subTphRes);
|
||||||
|
numOfVisitedPairs++;
|
||||||
|
}
|
||||||
|
|
||||||
|
subTphRes = tphInRel.getFirst();
|
||||||
|
|
||||||
|
int i = 2;
|
||||||
|
while(!containTPH(methodTphs,superTphRes) && (tphInRel.size()-i) >0) {
|
||||||
|
superTphRes = tphInRel.get(tphInRel.size()-i);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!containTPH(methodTphs, superTphRes)) {
|
||||||
|
result.put(new ExtendsConstraint(subTphRes, Type.getInternalName(Object.class), Relation.EXTENDS), null);
|
||||||
|
} else {
|
||||||
|
result.put(new ExtendsConstraint(subTphRes, superTphRes, Relation.EXTENDS), null);
|
||||||
|
result.put(new ExtendsConstraint(superTphRes, Type.getInternalName(Object.class), Relation.EXTENDS), null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
System.out.println("ZwischenResult: ");
|
||||||
|
result.forEach((c,hs)->{
|
||||||
|
if(c!=null) {
|
||||||
|
System.out.print(c.toString() + " -> ");
|
||||||
|
if(hs == null) {
|
||||||
|
System.out.print(" [] ");
|
||||||
|
}else {
|
||||||
|
hs.forEach(s->{
|
||||||
|
System.out.print(s + ", ");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
System.out.println();
|
||||||
|
});
|
||||||
|
System.out.println("----------------");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isTPHInConstraint(HashMap<TPHConstraint, HashSet<String>> result, String sub) {
|
||||||
|
for(TPHConstraint c : result.keySet()) {
|
||||||
|
if(c.getLeft().equals(sub))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean containTPH(ArrayList<TypePlaceholder> methodTphs, String sub) {
|
||||||
|
for(TypePlaceholder tph : methodTphs) {
|
||||||
|
if(tph.getName().equals(sub))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private TPHConstraint getKeyConstraint(HashMap<TPHConstraint, HashSet<String>> result, TPHConstraint toFind) {
|
||||||
|
for(TPHConstraint c : result.keySet()) {
|
||||||
|
if(c.containTPH(toFind.getLeft()) || c.containTPH(toFind.getRight()))
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
return new ExtendsConstraint(toFind.getRight(), Type.getInternalName(Object.class), Relation.EXTENDS);
|
||||||
|
}
|
||||||
|
|
||||||
|
private HashSet<String> getEqualsTPHs(HashMap<TPHConstraint,HashSet<String>> result, TPHConstraint toFind) {
|
||||||
|
for(TPHConstraint c : result.keySet()) {
|
||||||
|
if(c.containTPH(toFind.getLeft()) || c.containTPH(toFind.getRight()))
|
||||||
|
return result.get(c);
|
||||||
|
}
|
||||||
|
return new HashSet<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
private ArrayList<GenericInsertPair> simplifyPairs(String methodName, ArrayList<GenericInsertPair> allPairs, ArrayList<TPHConstraint> allCons) {
|
||||||
allPairs.forEach(p->System.out.print(p.TA1 + " < "+ p.TA2+ " ; "));
|
allPairs.forEach(p->System.out.print(p.TA1 + " < "+ p.TA2+ " ; "));
|
||||||
|
|
||||||
|
// 1. check if there are any cycles like L<R and R<L:
|
||||||
|
// a) yes => set L=R and:
|
||||||
|
// * remove both constraints
|
||||||
|
// * substitute L with R in all constraint
|
||||||
|
// b)no => go to next step
|
||||||
|
// 2. check the result of step 1 if there are any equal-constraints like L=R, M=R ..
|
||||||
|
// a) yes
|
||||||
|
// b) no
|
||||||
|
ArrayList<TPHConstraint> consToRemove = new ArrayList<>();
|
||||||
|
// step 1:
|
||||||
|
for(TPHConstraint c : allCons) {
|
||||||
|
|
||||||
|
String left = c.getLeft();
|
||||||
|
String right = c.getRight();
|
||||||
|
if(c.getRel() == Relation.EXTENDS) {
|
||||||
|
TPHConstraint revCon = getReverseConstraint(allCons,left,right);
|
||||||
|
if(revCon != null) {
|
||||||
|
revCon.setRel(Relation.EQUAL);
|
||||||
|
consToRemove.add(revCon);
|
||||||
|
c.setRel(Relation.EQUAL);
|
||||||
|
substituteTPH(allCons,left, right);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
System.out.println();
|
||||||
|
System.out.println("NEW ALL CONST: " + allCons.size());
|
||||||
|
allCons.forEach(c->System.out.println(c.toString()));
|
||||||
|
System.out.println("----------------");
|
||||||
|
allCons.removeAll(consToRemove);
|
||||||
|
System.out.println("AFTER DELETE ALL CONST: " + allCons.size());
|
||||||
|
allCons.forEach(c->System.out.println(c.toString()));
|
||||||
|
System.out.println("----------------");
|
||||||
if(allPairs.size() < 2)
|
if(allPairs.size() < 2)
|
||||||
return allPairs;
|
return allPairs;
|
||||||
|
|
||||||
@ -410,6 +693,26 @@ public class BytecodeGen implements ASTVisitor {
|
|||||||
return simplifiedPairs;
|
return simplifiedPairs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void substituteTPH(ArrayList<TPHConstraint> allCons,String left ,String right) {
|
||||||
|
allCons.forEach(c->{
|
||||||
|
if(c.getRel() == Relation.EXTENDS) {
|
||||||
|
if(c.getLeft().equals(left))
|
||||||
|
c.setLeft(right);
|
||||||
|
if(c.getRight().equals(left))
|
||||||
|
c.setRight(right);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private TPHConstraint getReverseConstraint(ArrayList<TPHConstraint> allCons, String left, String right) {
|
||||||
|
for(TPHConstraint c : allCons) {
|
||||||
|
if(c.getLeft().equals(right) && c.getRight().equals(left)){
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
private void removePair(ArrayList<GenericInsertPair> simplifiedPairs, TypePlaceholder typePlaceholder, TypePlaceholder typePlaceholder2) {
|
private void removePair(ArrayList<GenericInsertPair> simplifiedPairs, TypePlaceholder typePlaceholder, TypePlaceholder typePlaceholder2) {
|
||||||
for(GenericInsertPair p : simplifiedPairs) {
|
for(GenericInsertPair p : simplifiedPairs) {
|
||||||
if(p.TA1.equals(typePlaceholder) && p.TA2.equals(typePlaceholder2)) {
|
if(p.TA1.equals(typePlaceholder) && p.TA2.equals(typePlaceholder2)) {
|
||||||
@ -471,16 +774,16 @@ public class BytecodeGen implements ASTVisitor {
|
|||||||
// ??
|
// ??
|
||||||
@Override
|
@Override
|
||||||
public void visit(FieldVar fieldVar) {
|
public void visit(FieldVar fieldVar) {
|
||||||
|
System.out.println("In FieldVar ---");
|
||||||
// cw.newField(fieldVar.receiver.toString(), fieldVar.fieldVarName.toString(), fieldVar.getType().toString());
|
// cw.newField(fieldVar.receiver.toString(), fieldVar.fieldVarName.toString(), fieldVar.getType().toString());
|
||||||
FieldVisitor fv = cw.visitField(Opcodes.ACC_PRIVATE, fieldVar.fieldVarName, "L"+fieldVar.getType()+";", null, null);
|
FieldVisitor fv = cw.visitField(Opcodes.ACC_PRIVATE, fieldVar.fieldVarName, "L"+fieldVar.getType()+";", null, null);
|
||||||
fv.visitEnd();
|
fv.visitEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
// access flages?? modifiers
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(Field field) {
|
public void visit(Field field) {
|
||||||
FieldVisitor fv = cw.visitField(Opcodes.ACC_PRIVATE, field.getName(), "L"+field.getType().toString().replace(".", "/")+";", null, null);
|
System.out.println("In Field ---");
|
||||||
fv.visitEnd();
|
cw.visitField(field.modifier, field.getName(),resultSet.resolveType(field.getType()).resolvedType.acceptTV(new TypeToSignature()), null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -669,6 +972,7 @@ public class BytecodeGen implements ASTVisitor {
|
|||||||
Boolean inMethod = false;
|
Boolean inMethod = false;
|
||||||
final ArrayList<MethodAndTPH> ListOfMethodsAndTph = new ArrayList<>();
|
final ArrayList<MethodAndTPH> ListOfMethodsAndTph = new ArrayList<>();
|
||||||
final ArrayList<GenericInsertPair> allPairs = new ArrayList<>();
|
final ArrayList<GenericInsertPair> allPairs = new ArrayList<>();
|
||||||
|
final ArrayList<TPHConstraint> allCons = new ArrayList<>();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(TypePlaceholder tph) {
|
public void visit(TypePlaceholder tph) {
|
||||||
@ -683,6 +987,8 @@ public class BytecodeGen implements ASTVisitor {
|
|||||||
if(inMethod)
|
if(inMethod)
|
||||||
methodAndTph.getPairs().add(ag);
|
methodAndTph.getPairs().add(ag);
|
||||||
allPairs.add(ag);
|
allPairs.add(ag);
|
||||||
|
TPHConstraint con = new ExtendsConstraint(ag.TA1.getName(), ag.TA2.getName(), Relation.EXTENDS);
|
||||||
|
allCons.add(con);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -71,6 +71,7 @@ public class BytecodeGenMethod implements StatementVisitor {
|
|||||||
private SourceFile sf;
|
private SourceFile sf;
|
||||||
private IStatement statement = null;
|
private IStatement statement = null;
|
||||||
private boolean isReturnStmt = false;
|
private boolean isReturnStmt = false;
|
||||||
|
private boolean isParentBinary = false;
|
||||||
|
|
||||||
private boolean needDUP = false;
|
private boolean needDUP = false;
|
||||||
|
|
||||||
@ -211,7 +212,7 @@ public class BytecodeGenMethod implements StatementVisitor {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(BinaryExpr binary) {
|
public void visit(BinaryExpr binary) {
|
||||||
|
isParentBinary = true;
|
||||||
String lexpType = getResolvedType(binary.lexpr.getType());
|
String lexpType = getResolvedType(binary.lexpr.getType());
|
||||||
String rexpType = getResolvedType(binary.rexpr.getType());
|
String rexpType = getResolvedType(binary.rexpr.getType());
|
||||||
|
|
||||||
@ -242,12 +243,14 @@ public class BytecodeGenMethod implements StatementVisitor {
|
|||||||
needDUP = true;
|
needDUP = true;
|
||||||
|
|
||||||
binary.rexpr.accept(this);
|
binary.rexpr.accept(this);
|
||||||
|
|
||||||
|
isParentBinary = false;
|
||||||
|
|
||||||
if (!lexpType.equals(rexpType) && !rexpType.equals(largerType))
|
if (!lexpType.equals(rexpType) && !rexpType.equals(largerType))
|
||||||
doCast(rexpType, largerType);
|
doCast(rexpType, largerType);
|
||||||
|
|
||||||
Operator op = binary.operation;
|
Operator op = binary.operation;
|
||||||
|
|
||||||
switch (op) {
|
switch (op) {
|
||||||
case ADD:
|
case ADD:
|
||||||
doVisitAddOpInsn(largerType);
|
doVisitAddOpInsn(largerType);
|
||||||
@ -665,6 +668,7 @@ public class BytecodeGenMethod implements StatementVisitor {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(MethodCall methodCall) {
|
public void visit(MethodCall methodCall) {
|
||||||
|
boolean parentBinary = isParentBinary;
|
||||||
System.out.println("In MethodCall = " + methodCall.name);
|
System.out.println("In MethodCall = " + methodCall.name);
|
||||||
String receiverName = getResolvedType(methodCall.receiver.getType());
|
String receiverName = getResolvedType(methodCall.receiver.getType());
|
||||||
System.out.println("Methods of " + receiverName + " ");
|
System.out.println("Methods of " + receiverName + " ");
|
||||||
@ -681,7 +685,7 @@ public class BytecodeGenMethod implements StatementVisitor {
|
|||||||
|
|
||||||
java.lang.reflect.Method[] methods = cLoader.loadClass(clazz).getMethods();
|
java.lang.reflect.Method[] methods = cLoader.loadClass(clazz).getMethods();
|
||||||
System.out.println("Methods of " + receiverName + " ");
|
System.out.println("Methods of " + receiverName + " ");
|
||||||
methodRefl = getMethod(methodCall.name,methods);
|
methodRefl = getMethod(methodCall.name,methodCall.arglist.getArguments().size(),methods);
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
// try {
|
// try {
|
||||||
@ -736,16 +740,19 @@ public class BytecodeGenMethod implements StatementVisitor {
|
|||||||
System.out.println("Methodcall type : " + resultSet.resolveType(methodCall.getType()).resolvedType.acceptTV(new TypeToDescriptor()));
|
System.out.println("Methodcall type : " + resultSet.resolveType(methodCall.getType()).resolvedType.acceptTV(new TypeToDescriptor()));
|
||||||
String mDesc = "";
|
String mDesc = "";
|
||||||
List<Boolean> argListMethCall = new LinkedList<>();
|
List<Boolean> argListMethCall = new LinkedList<>();
|
||||||
|
String receiverRefl="";
|
||||||
if(methodRefl == null) {
|
if(methodRefl == null) {
|
||||||
MethodFromMethodCall method = new MethodFromMethodCall(methodCall.arglist, methodCall.getType(),
|
MethodFromMethodCall method = new MethodFromMethodCall(methodCall.arglist, methodCall.getType(),
|
||||||
receiverName, genericsAndBoundsMethod, genericsAndBounds);
|
receiverName, genericsAndBoundsMethod, genericsAndBounds);
|
||||||
mDesc = method.accept(new DescriptorToString(resultSet));
|
mDesc = method.accept(new DescriptorToString(resultSet));
|
||||||
methodCall.arglist.accept(this);
|
methodCall.arglist.accept(this);
|
||||||
} else {
|
} else {
|
||||||
|
receiverRefl = methodRefl.getAnnotatedReceiverType().getType().toString();
|
||||||
for(Parameter p:methodRefl.getParameters()) {
|
for(Parameter p:methodRefl.getParameters()) {
|
||||||
System.out.println(p.getName() + " und is Primitive = " + p.getType().isPrimitive());
|
System.out.println(p.getName() + " und is Primitive = " + p.getType().isPrimitive());
|
||||||
argListMethCall.add(p.getType().isPrimitive());
|
argListMethCall.add(p.getType().isPrimitive());
|
||||||
}
|
}
|
||||||
|
System.out.println("Receiver = " + methodRefl.getAnnotatedReceiverType().getType().toString());
|
||||||
mDesc = getMethodDesc(methodRefl);
|
mDesc = getMethodDesc(methodRefl);
|
||||||
for (Expression al : methodCall.arglist.getArguments()) {
|
for (Expression al : methodCall.arglist.getArguments()) {
|
||||||
statement = new ArgumentExpr(al);
|
statement = new ArgumentExpr(al);
|
||||||
@ -761,7 +768,7 @@ public class BytecodeGenMethod implements StatementVisitor {
|
|||||||
// methodCall.arglist.accept(this);
|
// methodCall.arglist.accept(this);
|
||||||
|
|
||||||
// is methodCall.receiver functional Interface)?
|
// is methodCall.receiver functional Interface)?
|
||||||
if (varsFunInterface.contains(methodCall.receiver.getType())) {
|
if (varsFunInterface.contains(methodCall.receiver.getType()) || (methodRefl!= null && receiverRefl.contains("interface"))) {
|
||||||
mv.visitMethodInsn(Opcodes.INVOKEINTERFACE, clazz.replace(".", "/"), methodCall.name,
|
mv.visitMethodInsn(Opcodes.INVOKEINTERFACE, clazz.replace(".", "/"), methodCall.name,
|
||||||
mDesc, true);
|
mDesc, true);
|
||||||
} else {
|
} else {
|
||||||
@ -780,8 +787,8 @@ public class BytecodeGenMethod implements StatementVisitor {
|
|||||||
if(isBinaryExp)
|
if(isBinaryExp)
|
||||||
doUnboxing(getResolvedType(methodCall.getType()));
|
doUnboxing(getResolvedType(methodCall.getType()));
|
||||||
}
|
}
|
||||||
|
System.out.println("ISParent Binary = "+isParentBinary +" -> " + parentBinary);
|
||||||
if(methodRefl == null/* && !isReturnStmt*/) {
|
if(methodRefl == null && (parentBinary || !isReturnStmt)) {
|
||||||
if(isBinaryExp)
|
if(isBinaryExp)
|
||||||
doUnboxing(getResolvedType(methodCall.getType()));
|
doUnboxing(getResolvedType(methodCall.getType()));
|
||||||
}
|
}
|
||||||
@ -790,12 +797,13 @@ public class BytecodeGenMethod implements StatementVisitor {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param name name of a method
|
* @param name name of a method
|
||||||
|
* @param i number of parameters
|
||||||
* @param methods all methods of a class
|
* @param methods all methods of a class
|
||||||
* @return the method in the class file which its name equals the given methode name
|
* @return the method in the class file which its name equals the given methode name
|
||||||
*/
|
*/
|
||||||
private java.lang.reflect.Method getMethod(String name, java.lang.reflect.Method[] methods) {
|
private java.lang.reflect.Method getMethod(String name, int i, java.lang.reflect.Method[] methods) {
|
||||||
for(java.lang.reflect.Method m : methods) {
|
for(java.lang.reflect.Method m : methods) {
|
||||||
if(name.equals(m.getName())) {
|
if(name.equals(m.getName()) && i == m.getParameterCount()) {
|
||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1087,13 +1095,16 @@ public class BytecodeGenMethod implements StatementVisitor {
|
|||||||
visitIntegerLiteral(((Integer) value).intValue(), false);
|
visitIntegerLiteral(((Integer) value).intValue(), false);
|
||||||
break;
|
break;
|
||||||
case "java/lang/Long":
|
case "java/lang/Long":
|
||||||
visitLongLiteral(((Double) value).longValue(), true);
|
visitLongLiteral(((Integer) value).longValue(), true);
|
||||||
break;
|
break;
|
||||||
case "java/lang/Float":
|
case "java/lang/Float":
|
||||||
visitFloatLiteral(((Double) value).floatValue());
|
visitFloatLiteral(((Double) value).floatValue());
|
||||||
break;
|
break;
|
||||||
case "java/lang/Double":
|
case "java/lang/Double":
|
||||||
visitDoubleLiteral((Double) value);
|
if(value instanceof Double)
|
||||||
|
visitDoubleLiteral((Double) value);
|
||||||
|
if(value instanceof Integer)
|
||||||
|
visitDoubleLiteral(((Integer) value).doubleValue());
|
||||||
break;
|
break;
|
||||||
case "java/lang/Character":
|
case "java/lang/Character":
|
||||||
visitCharLiteral((Character) value);
|
visitCharLiteral((Character) value);
|
||||||
@ -1252,8 +1263,9 @@ public class BytecodeGenMethod implements StatementVisitor {
|
|||||||
// array slot onto the top of the operand stack.
|
// array slot onto the top of the operand stack.
|
||||||
assignLeftSide.field.receiver.accept(this);
|
assignLeftSide.field.receiver.accept(this);
|
||||||
this.rightSideTemp.accept(this);
|
this.rightSideTemp.accept(this);
|
||||||
|
System.out.println("Receiver = " + getResolvedType(assignLeftSide.field.receiver.getType()));
|
||||||
mv.visitFieldInsn(Opcodes.PUTFIELD, getResolvedType(assignLeftSide.field.receiver.getType()),
|
mv.visitFieldInsn(Opcodes.PUTFIELD, getResolvedType(assignLeftSide.field.receiver.getType()),
|
||||||
assignLeftSide.field.fieldVarName, getResolvedType(assignLeftSide.field.getType()));
|
assignLeftSide.field.fieldVarName, "L"+getResolvedType(assignLeftSide.field.getType())+";");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -0,0 +1,9 @@
|
|||||||
|
package de.dhbwstuttgart.bytecode.constraint;
|
||||||
|
|
||||||
|
public class EqualConstraint extends TPHConstraint {
|
||||||
|
|
||||||
|
public EqualConstraint(String left, String right, Relation rel) {
|
||||||
|
super(left, right, rel);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,9 @@
|
|||||||
|
package de.dhbwstuttgart.bytecode.constraint;
|
||||||
|
|
||||||
|
public class ExtendsConstraint extends TPHConstraint {
|
||||||
|
|
||||||
|
public ExtendsConstraint(String left, String right, Relation rel) {
|
||||||
|
super(left, right, rel);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
55
src/de/dhbwstuttgart/bytecode/constraint/TPHConstraint.java
Normal file
55
src/de/dhbwstuttgart/bytecode/constraint/TPHConstraint.java
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
package de.dhbwstuttgart.bytecode.constraint;
|
||||||
|
|
||||||
|
public class TPHConstraint {
|
||||||
|
protected String left;
|
||||||
|
protected String right;
|
||||||
|
protected Relation rel;
|
||||||
|
public enum Relation{
|
||||||
|
EXTENDS, EQUAL
|
||||||
|
}
|
||||||
|
|
||||||
|
public TPHConstraint(String left, String right, Relation rel) {
|
||||||
|
this.left = left;
|
||||||
|
this.right = right;
|
||||||
|
this.rel = rel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLeft() {
|
||||||
|
return left;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public String getRight() {
|
||||||
|
return right;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public Relation getRel() {
|
||||||
|
return rel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLeft(String left) {
|
||||||
|
this.left = left;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRight(String right) {
|
||||||
|
this.right = right;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRel(Relation rel) {
|
||||||
|
this.rel = rel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean containTPH(String tph) {
|
||||||
|
return left.equals(tph)||right.equals(tph);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
if(rel == Relation.EXTENDS) {
|
||||||
|
return left + " < " + right;
|
||||||
|
}else {
|
||||||
|
return left + " = " + right;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -21,12 +21,14 @@ import java.util.*;
|
|||||||
public class StatementGenerator {
|
public class StatementGenerator {
|
||||||
|
|
||||||
private JavaClassRegistry reg;
|
private JavaClassRegistry reg;
|
||||||
|
private Map<String, RefTypeOrTPHOrWildcardOrGeneric> fields; //PL 2018-11-01 fields eingefuegt, damit die fields immer die gleiche TPH bekommen
|
||||||
private Map<String, RefTypeOrTPHOrWildcardOrGeneric> localVars;
|
private Map<String, RefTypeOrTPHOrWildcardOrGeneric> localVars;
|
||||||
private GenericsRegistry generics;
|
private GenericsRegistry generics;
|
||||||
|
|
||||||
public StatementGenerator(JavaClassRegistry reg, GenericsRegistry generics, Map<String, RefTypeOrTPHOrWildcardOrGeneric> localVars){
|
public StatementGenerator(JavaClassRegistry reg, GenericsRegistry generics, Map<String, RefTypeOrTPHOrWildcardOrGeneric> fields, Map<String, RefTypeOrTPHOrWildcardOrGeneric> localVars){
|
||||||
this.reg = reg;
|
this.reg = reg;
|
||||||
this.generics = generics;
|
this.generics = generics;
|
||||||
|
this.fields = fields;
|
||||||
this.localVars = localVars;
|
this.localVars = localVars;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -238,9 +240,14 @@ public class StatementGenerator {
|
|||||||
if(localVars.get(expression) != null){
|
if(localVars.get(expression) != null){
|
||||||
return new LocalVar(expression, localVars.get(expression), offset);
|
return new LocalVar(expression, localVars.get(expression), offset);
|
||||||
}else{
|
}else{
|
||||||
|
if(fields.get(expression) != null){//PL 2018-11-01 fields eingefuegt, damit die fields immer die gleiche TPH bekommen
|
||||||
|
return new FieldVar(new This(offset), expression, fields.get(expression), offset);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
//kann eigentlich nicht vorkommen
|
||||||
//Dann Muss es ein Feld sein!
|
//Dann Muss es ein Feld sein!
|
||||||
return new FieldVar(new This(offset), expression, TypePlaceholder.fresh(offset), offset);
|
return new FieldVar(new This(offset), expression, TypePlaceholder.fresh(offset), offset);
|
||||||
}
|
}}
|
||||||
}
|
}
|
||||||
return generateFieldVarOrClassname(expression, offset);
|
return generateFieldVarOrClassname(expression, offset);
|
||||||
}
|
}
|
||||||
@ -896,7 +903,7 @@ public class StatementGenerator {
|
|||||||
for(FormalParameter param : params.getFormalparalist()){
|
for(FormalParameter param : params.getFormalparalist()){
|
||||||
lambdaLocals.put(param.getName(), param.getType());
|
lambdaLocals.put(param.getName(), param.getType());
|
||||||
}
|
}
|
||||||
StatementGenerator lambdaGenerator = new StatementGenerator(reg, generics, lambdaLocals);
|
StatementGenerator lambdaGenerator = new StatementGenerator(reg, generics, fields, lambdaLocals);
|
||||||
|
|
||||||
Block block;
|
Block block;
|
||||||
if(expression.lambdaBody().expression() != null){
|
if(expression.lambdaBody().expression() != null){
|
||||||
|
@ -33,6 +33,7 @@ public class SyntaxTreeGenerator{
|
|||||||
private final GenericsRegistry globalGenerics;
|
private final GenericsRegistry globalGenerics;
|
||||||
private String pkgName = "";
|
private String pkgName = "";
|
||||||
Set<JavaClassName> imports = new HashSet();
|
Set<JavaClassName> imports = new HashSet();
|
||||||
|
private Map<String, RefTypeOrTPHOrWildcardOrGeneric> fields = new HashMap<>(); //PL 2018-11-01 fields eingefuegt, damit die fields immer die gleiche TPH bekommen
|
||||||
|
|
||||||
List<Statement> fieldInitializations = new ArrayList<>();
|
List<Statement> fieldInitializations = new ArrayList<>();
|
||||||
|
|
||||||
@ -122,7 +123,7 @@ public class SyntaxTreeGenerator{
|
|||||||
private Method convert(int modifiers, Java8Parser.MethodHeaderContext header, Java8Parser.MethodBodyContext body,
|
private Method convert(int modifiers, Java8Parser.MethodHeaderContext header, Java8Parser.MethodBodyContext body,
|
||||||
JavaClassName parentClass, RefType superClass, GenericsRegistry localGenerics) {
|
JavaClassName parentClass, RefType superClass, GenericsRegistry localGenerics) {
|
||||||
|
|
||||||
StatementGenerator stmtGen = new StatementGenerator(reg, localGenerics, new HashMap<>());
|
StatementGenerator stmtGen = new StatementGenerator(reg, localGenerics, fields, new HashMap<>());
|
||||||
|
|
||||||
String name = header.methodDeclarator().Identifier().getText();
|
String name = header.methodDeclarator().Identifier().getText();
|
||||||
GenericDeclarationList gtvDeclarations = new GenericDeclarationList(new ArrayList<>(), header.getStart());
|
GenericDeclarationList gtvDeclarations = new GenericDeclarationList(new ArrayList<>(), header.getStart());
|
||||||
@ -346,6 +347,7 @@ public class SyntaxTreeGenerator{
|
|||||||
}
|
}
|
||||||
for(Java8Parser.VariableDeclaratorContext varCtx : fieldDeclarationContext.variableDeclaratorList().variableDeclarator()){
|
for(Java8Parser.VariableDeclaratorContext varCtx : fieldDeclarationContext.variableDeclaratorList().variableDeclarator()){
|
||||||
String fieldName = convert(varCtx.variableDeclaratorId());
|
String fieldName = convert(varCtx.variableDeclaratorId());
|
||||||
|
fields.put(fieldName, fieldType);
|
||||||
if(varCtx.variableInitializer() != null){
|
if(varCtx.variableInitializer() != null){
|
||||||
initializeField(varCtx, fieldType, generics);
|
initializeField(varCtx, fieldType, generics);
|
||||||
}
|
}
|
||||||
@ -360,7 +362,7 @@ public class SyntaxTreeGenerator{
|
|||||||
|
|
||||||
// Initialize a field by creating implicit constructor.
|
// Initialize a field by creating implicit constructor.
|
||||||
private void initializeField(Java8Parser.VariableDeclaratorContext ctx, RefTypeOrTPHOrWildcardOrGeneric typeOfField, GenericsRegistry generics){
|
private void initializeField(Java8Parser.VariableDeclaratorContext ctx, RefTypeOrTPHOrWildcardOrGeneric typeOfField, GenericsRegistry generics){
|
||||||
StatementGenerator statementGenerator = new StatementGenerator(reg, generics, new HashMap<>());
|
StatementGenerator statementGenerator = new StatementGenerator(reg, generics, fields, new HashMap<>());
|
||||||
fieldInitializations.add(statementGenerator.generateFieldAssignment(ctx, typeOfField));
|
fieldInitializations.add(statementGenerator.generateFieldAssignment(ctx, typeOfField));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@ import de.dhbwstuttgart.exceptions.NotImplementedException;
|
|||||||
import de.dhbwstuttgart.exceptions.TypeinferenceException;
|
import de.dhbwstuttgart.exceptions.TypeinferenceException;
|
||||||
import de.dhbwstuttgart.parser.NullToken;
|
import de.dhbwstuttgart.parser.NullToken;
|
||||||
import de.dhbwstuttgart.parser.SyntaxTreeGenerator.AssignToLocal;
|
import de.dhbwstuttgart.parser.SyntaxTreeGenerator.AssignToLocal;
|
||||||
|
import de.dhbwstuttgart.parser.scope.JavaClassName;
|
||||||
import de.dhbwstuttgart.syntaxtree.*;
|
import de.dhbwstuttgart.syntaxtree.*;
|
||||||
import de.dhbwstuttgart.syntaxtree.factory.ASTFactory;
|
import de.dhbwstuttgart.syntaxtree.factory.ASTFactory;
|
||||||
import de.dhbwstuttgart.syntaxtree.factory.NameGenerator;
|
import de.dhbwstuttgart.syntaxtree.factory.NameGenerator;
|
||||||
@ -18,6 +19,7 @@ import de.dhbwstuttgart.typeinference.unify.model.PairOperator;
|
|||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
public class TYPEStmt implements StatementVisitor{
|
public class TYPEStmt implements StatementVisitor{
|
||||||
|
|
||||||
@ -370,25 +372,60 @@ public class TYPEStmt implements StatementVisitor{
|
|||||||
//PL 2018-06-23 Sie haben einen Typ. Der muesste hier eingefuegt werden
|
//PL 2018-06-23 Sie haben einen Typ. Der muesste hier eingefuegt werden
|
||||||
//wie hier fuer double gezeigt. Im Momment auskommentiert, weil zu wenige Literaltypen
|
//wie hier fuer double gezeigt. Im Momment auskommentiert, weil zu wenige Literaltypen
|
||||||
//funktionieren
|
//funktionieren
|
||||||
|
if (literal.value instanceof Short) {
|
||||||
|
constraintsSet.addUndConstraint(new Pair(literal.getType(), shortt, PairOperator.EQUALSDOT));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (literal.value instanceof Byte) {
|
||||||
|
constraintsSet.addUndConstraint(new Pair(literal.getType(), bytee, PairOperator.EQUALSDOT));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (literal.value instanceof Float) {
|
||||||
|
constraintsSet.addUndConstraint(new Pair(literal.getType(), floatt, PairOperator.EQUALSDOT));
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (literal.value instanceof Double) {
|
if (literal.value instanceof Double) {
|
||||||
constraintsSet.addUndConstraint(new Pair(literal.getType(), doublee, PairOperator.EQUALSDOT));
|
constraintsSet.addUndConstraint(new Pair(literal.getType(), doublee, PairOperator.EQUALSDOT));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (literal.value instanceof Double) {
|
if (literal.value instanceof Long) {
|
||||||
constraintsSet.addUndConstraint(new Pair(literal.getType(), longg, PairOperator.EQUALSDOT));
|
constraintsSet.addUndConstraint(new Pair(literal.getType(), longg, PairOperator.EQUALSDOT));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (literal.value instanceof Integer) {
|
if (literal.value instanceof Integer) {
|
||||||
//constraintsSet.addUndConstraint(new Pair(literal.getType(),integer, PairOperator.EQUALSDOT));
|
//constraintsSet.addUndConstraint(new Pair(literal.getType(),integer, PairOperator.EQUALSDOT));
|
||||||
// /*
|
// /*
|
||||||
|
HashSet<JavaClassName> clNames = info.getAvailableClasses().stream().map(x -> x.getClassName()).collect(Collectors.toCollection(HashSet::new));
|
||||||
Set<Constraint> oderConstraints = new HashSet<>();
|
Set<Constraint> oderConstraints = new HashSet<>();
|
||||||
Constraint constraint = new Constraint();
|
Constraint constraint = new Constraint();
|
||||||
constraint.add(new Pair(literal.getType(), integer, PairOperator.EQUALSDOT));
|
constraint.add(new Pair(literal.getType(), integer, PairOperator.EQUALSDOT));
|
||||||
oderConstraints.add(constraint);
|
oderConstraints.add(constraint);
|
||||||
constraint = new Constraint();
|
if (clNames.stream().filter(x -> x.toString().equals("java.lang.Double")).findAny().isPresent()) {
|
||||||
constraint.add(new Pair(literal.getType(), doublee, PairOperator.EQUALSDOT));
|
constraint = new Constraint();
|
||||||
oderConstraints.add(constraint);
|
constraint.add(new Pair(literal.getType(), doublee, PairOperator.EQUALSDOT));
|
||||||
constraintsSet.addOderConstraint(oderConstraints);
|
oderConstraints.add(constraint);
|
||||||
|
}
|
||||||
|
if (clNames.stream().filter(x -> x.toString().equals("java.lang.Long")).findAny().isPresent()) {
|
||||||
|
constraint = new Constraint();
|
||||||
|
constraint.add(new Pair(literal.getType(), longg, PairOperator.EQUALSDOT));
|
||||||
|
oderConstraints.add(constraint);
|
||||||
|
}
|
||||||
|
if (clNames.stream().filter(x -> x.toString().equals("java.lang.Float")).findAny().isPresent()) {
|
||||||
|
constraint = new Constraint();
|
||||||
|
constraint.add(new Pair(literal.getType(), floatt, PairOperator.EQUALSDOT));
|
||||||
|
oderConstraints.add(constraint);
|
||||||
|
}
|
||||||
|
if (clNames.stream().filter(x -> x.toString().equals("java.lang.Short")).findAny().isPresent()) {
|
||||||
|
constraint = new Constraint();
|
||||||
|
constraint.add(new Pair(literal.getType(), shortt, PairOperator.EQUALSDOT));
|
||||||
|
oderConstraints.add(constraint);
|
||||||
|
}
|
||||||
|
if (clNames.stream().filter(x -> x.toString().equals("java.lang.Byte")).findAny().isPresent()) {
|
||||||
|
constraint = new Constraint();
|
||||||
|
constraint.add(new Pair(literal.getType(), bytee, PairOperator.EQUALSDOT));
|
||||||
|
oderConstraints.add(constraint);
|
||||||
|
}
|
||||||
|
constraintsSet.addOderConstraint(oderConstraints);
|
||||||
// */
|
// */
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -484,6 +521,8 @@ public class TYPEStmt implements StatementVisitor{
|
|||||||
@Override
|
@Override
|
||||||
public void visit(AssignToField assignLeftSide) {
|
public void visit(AssignToField assignLeftSide) {
|
||||||
//Hier ist kein Code nötig. Es werden keine extra Constraints generiert
|
//Hier ist kein Code nötig. Es werden keine extra Constraints generiert
|
||||||
|
//HIER muss Code rein PL 2018-10-24
|
||||||
|
assignLeftSide.field.accept(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -513,8 +552,10 @@ public class TYPEStmt implements StatementVisitor{
|
|||||||
|
|
||||||
RefTypeOrTPHOrWildcardOrGeneric receiverType = new RefType(assumption.getReceiver().getClassName(), params, forMethod.getOffset());
|
RefTypeOrTPHOrWildcardOrGeneric receiverType = new RefType(assumption.getReceiver().getClassName(), params, forMethod.getOffset());
|
||||||
*/
|
*/
|
||||||
methodConstraint.add(new Pair(forMethod.receiver.getType(), assumption.getReceiverType(resolver),
|
|
||||||
PairOperator.SMALLERDOT));
|
RefTypeOrTPHOrWildcardOrGeneric retType = assumption.getReceiverType(resolver);
|
||||||
|
methodConstraint.add(new Pair(forMethod.receiver.getType(), retType,
|
||||||
|
PairOperator.SMALLERDOT));
|
||||||
methodConstraint.add(new Pair(assumption.getReturnType(resolver), forMethod.getType(),
|
methodConstraint.add(new Pair(assumption.getReturnType(resolver), forMethod.getType(),
|
||||||
PairOperator.EQUALSDOT));
|
PairOperator.EQUALSDOT));
|
||||||
methodConstraint.addAll(generateParameterConstraints(forMethod, assumption, info, resolver));
|
methodConstraint.addAll(generateParameterConstraints(forMethod, assumption, info, resolver));
|
||||||
|
@ -782,16 +782,31 @@ public class RuleSet implements IRuleSet{
|
|||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
|
|
||||||
Set<UnifyPair> result = new HashSet<UnifyPair>();
|
Set<UnifyPair> result = new HashSet<UnifyPair>();
|
||||||
|
if (pair.getPairOp() == PairOperator.SMALLERDOT) {
|
||||||
result.add(new UnifyPair(funNLhsType.getTypeParams().get(funNLhsType.getTypeParams().size()-1), funNRhsType.getTypeParams().get(funNRhsType.getTypeParams().size()-1), PairOperator.SMALLERDOT, pair.getSubstitution(), pair.getBasePair()));
|
result.add(new UnifyPair(funNLhsType.getTypeParams().get(funNLhsType.getTypeParams().size()-1), funNRhsType.getTypeParams().get(funNRhsType.getTypeParams().size()-1), PairOperator.SMALLERDOT, pair.getSubstitution(), pair.getBasePair()));
|
||||||
for(int i = 0; i < funNLhsType.getTypeParams().size()-1; i++) {
|
for(int i = 0; i < funNLhsType.getTypeParams().size()-1; i++) {
|
||||||
result.add(new UnifyPair(funNRhsType.getTypeParams().get(i), funNLhsType.getTypeParams().get(i), PairOperator.SMALLERDOT, pair.getSubstitution(), pair.getBasePair()));
|
result.add(new UnifyPair(funNRhsType.getTypeParams().get(i), funNLhsType.getTypeParams().get(i), PairOperator.SMALLERDOT, pair.getSubstitution(), pair.getBasePair()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {// pair.getPairOp() == PairOperator.EQUALDOT
|
||||||
|
result.add(new UnifyPair(funNLhsType.getTypeParams().get(funNLhsType.getTypeParams().size()-1), funNRhsType.getTypeParams().get(funNRhsType.getTypeParams().size()-1), PairOperator.EQUALSDOT, pair.getSubstitution(), pair.getBasePair()));
|
||||||
|
for(int i = 0; i < funNLhsType.getTypeParams().size()-1; i++) {
|
||||||
|
result.add(new UnifyPair(funNRhsType.getTypeParams().get(i), funNLhsType.getTypeParams().get(i), PairOperator.EQUALSDOT, pair.getSubstitution(), pair.getBasePair()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
result.stream().forEach(x -> { UnifyType l = x.getLhsType();
|
result.stream().forEach(x -> { UnifyType l = x.getLhsType();
|
||||||
if (l instanceof PlaceholderType) { ((PlaceholderType)l).disableWildcardtable(); }
|
if (l instanceof PlaceholderType) { ((PlaceholderType)l).disableWildcardtable(); }
|
||||||
UnifyType r = x.getRhsType();
|
UnifyType r = x.getRhsType();
|
||||||
if (r instanceof PlaceholderType) { ((PlaceholderType)r).disableWildcardtable(); }
|
if (r instanceof PlaceholderType) { ((PlaceholderType)r).disableWildcardtable(); }
|
||||||
} );
|
} );
|
||||||
|
try {
|
||||||
|
logFile.write("FUNgreater: " + pair + "\n");
|
||||||
|
logFile.write("FUNred: " + result + "\n");
|
||||||
|
logFile.flush();
|
||||||
|
}
|
||||||
|
catch (IOException e) {
|
||||||
|
System.out.println("logFile-Error");
|
||||||
|
}
|
||||||
return Optional.of(result);
|
return Optional.of(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -834,6 +849,14 @@ public class RuleSet implements IRuleSet{
|
|||||||
UnifyType r = x.getRhsType();
|
UnifyType r = x.getRhsType();
|
||||||
if (r instanceof PlaceholderType) { ((PlaceholderType)r).disableWildcardtable(); }
|
if (r instanceof PlaceholderType) { ((PlaceholderType)r).disableWildcardtable(); }
|
||||||
} );
|
} );
|
||||||
|
try {
|
||||||
|
logFile.write("FUNgreater: " + pair + "\n");
|
||||||
|
logFile.write("FUNgreater: " + result + "\n");
|
||||||
|
logFile.flush();
|
||||||
|
}
|
||||||
|
catch (IOException e) {
|
||||||
|
System.out.println("lofFile-Error");
|
||||||
|
}
|
||||||
return Optional.of(result);
|
return Optional.of(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -876,6 +899,14 @@ public class RuleSet implements IRuleSet{
|
|||||||
UnifyType r = x.getRhsType();
|
UnifyType r = x.getRhsType();
|
||||||
if (r instanceof PlaceholderType) { ((PlaceholderType)r).disableWildcardtable(); }
|
if (r instanceof PlaceholderType) { ((PlaceholderType)r).disableWildcardtable(); }
|
||||||
} );
|
} );
|
||||||
|
try {
|
||||||
|
logFile.write("FUNgreater: " + pair + "\n");
|
||||||
|
logFile.write("FUNsmaller: " + result + "\n");
|
||||||
|
logFile.flush();
|
||||||
|
}
|
||||||
|
catch (IOException e) {
|
||||||
|
System.out.println("lofFile-Error");
|
||||||
|
}
|
||||||
return Optional.of(result);
|
return Optional.of(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
43
test/bytecode/FieldTest.java
Normal file
43
test/bytecode/FieldTest.java
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
package bytecode;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
|
||||||
|
import org.junit.BeforeClass;
|
||||||
|
import org.junit.Test;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.net.URLClassLoader;
|
||||||
|
|
||||||
|
import de.dhbwstuttgart.core.JavaTXCompiler;
|
||||||
|
|
||||||
|
public class FieldTest {
|
||||||
|
|
||||||
|
private static String path;
|
||||||
|
private static File fileToTest;
|
||||||
|
private static JavaTXCompiler compiler;
|
||||||
|
private static ClassLoader loader;
|
||||||
|
private static Class<?> classToTest;
|
||||||
|
private static String pathToClassFile;
|
||||||
|
private static Object instanceOfClass;
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
public static void setUpBeforeClass() throws Exception {
|
||||||
|
path = System.getProperty("user.dir")+"/test/bytecode/javFiles/Field.jav";
|
||||||
|
fileToTest = new File(path);
|
||||||
|
compiler = new JavaTXCompiler(fileToTest);
|
||||||
|
compiler.generateBytecode(System.getProperty("user.dir")+"/testBytecode/generatedBC/");
|
||||||
|
pathToClassFile = System.getProperty("user.dir")+"/testBytecode/generatedBC/";
|
||||||
|
loader = new URLClassLoader(new URL[] {new URL("file://"+pathToClassFile)});
|
||||||
|
classToTest = loader.loadClass("Field");
|
||||||
|
instanceOfClass = classToTest.getDeclaredConstructor().newInstance();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test() {
|
||||||
|
Field[] fields = classToTest.getFields();
|
||||||
|
assertEquals(1, fields.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -32,9 +32,9 @@ public class MatrixOpTest {
|
|||||||
fileToTest = new File(path);
|
fileToTest = new File(path);
|
||||||
compiler = new JavaTXCompiler(fileToTest);
|
compiler = new JavaTXCompiler(fileToTest);
|
||||||
pathToClassFile = System.getProperty("user.dir")+"/testBytecode/generatedBC/";
|
pathToClassFile = System.getProperty("user.dir")+"/testBytecode/generatedBC/";
|
||||||
compiler.generateBytecode(pathToClassFile);
|
// compiler.generateBytecode(pathToClassFile);
|
||||||
loader = new URLClassLoader(new URL[] {new URL("file://"+pathToClassFile)});
|
// loader = new URLClassLoader(new URL[] {new URL("file://"+pathToClassFile)});
|
||||||
classToTest = loader.loadClass("MatrixOP");
|
// classToTest = loader.loadClass("MatrixOP");
|
||||||
/*
|
/*
|
||||||
Vector<Vector<Integer>> vv = new Vector<Vector<Integer>>();
|
Vector<Vector<Integer>> vv = new Vector<Vector<Integer>>();
|
||||||
Vector<Integer> v1 = new Vector<Integer> ();
|
Vector<Integer> v1 = new Vector<Integer> ();
|
||||||
|
@ -24,28 +24,28 @@ public class OverloadingSortingTest {
|
|||||||
private static Class<?> classOL2;
|
private static Class<?> classOL2;
|
||||||
private static Object instanceOfClassOL2;
|
private static Object instanceOfClassOL2;
|
||||||
|
|
||||||
@BeforeClass
|
@Test
|
||||||
public static void setUpBeforeClass() throws Exception {
|
public void generateBC() throws Exception {
|
||||||
path = System.getProperty("user.dir")+"/test/bytecode/javFiles/Sorting.jav";
|
path = System.getProperty("user.dir")+"/test/bytecode/javFiles/Sorting.jav";
|
||||||
fileToTest = new File(path);
|
fileToTest = new File(path);
|
||||||
compiler = new JavaTXCompiler(fileToTest);
|
compiler = new JavaTXCompiler(fileToTest);
|
||||||
pathToClassFile = System.getProperty("user.dir")+"/testBytecode/generatedBC/";
|
pathToClassFile = System.getProperty("user.dir")+"/testBytecode/generatedBC/";
|
||||||
compiler.generateBytecode(pathToClassFile);
|
compiler.generateBytecode(pathToClassFile);
|
||||||
loader = new URLClassLoader(new URL[] {new URL("file://"+pathToClassFile)});
|
// loader = new URLClassLoader(new URL[] {new URL("file://"+pathToClassFile)});
|
||||||
classToTest = loader.loadClass("Sorting");
|
// classToTest = loader.loadClass("Sorting");
|
||||||
instanceOfClass = classToTest.getDeclaredConstructor().newInstance();
|
// instanceOfClass = classToTest.getDeclaredConstructor().newInstance();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
// @Test
|
||||||
public void test() throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
|
// public void test() throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
|
||||||
Method meth = classToTest.getDeclaredMethod("merge", classToTest);
|
// Method meth = classToTest.getDeclaredMethod("merge", classToTest);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@Test
|
// @Test
|
||||||
public void test2() throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
|
// public void test2() throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
|
||||||
Method meth = classToTest.getDeclaredMethod("test", classOL2);
|
// Method meth = classToTest.getDeclaredMethod("test", classOL2);
|
||||||
String res = (String) meth.invoke(instanceOfClass, instanceOfClassOL2);
|
// String res = (String) meth.invoke(instanceOfClass, instanceOfClassOL2);
|
||||||
assertEquals("Overloading2", res);
|
// assertEquals("Overloading2", res);
|
||||||
}
|
// }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
52
test/bytecode/YTest.java
Normal file
52
test/bytecode/YTest.java
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
package bytecode;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.net.URLClassLoader;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import de.dhbwstuttgart.core.JavaTXCompiler;
|
||||||
|
|
||||||
|
public class YTest {
|
||||||
|
private static String path;
|
||||||
|
private static File fileToTest;
|
||||||
|
private static JavaTXCompiler compiler;
|
||||||
|
private static ClassLoader loader;
|
||||||
|
private static Class<?> classToTest;
|
||||||
|
private static String pathToClassFile;
|
||||||
|
private static Object instanceOfClass;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void generateBC() throws Exception {
|
||||||
|
path = System.getProperty("user.dir")+"/test/bytecode/javFiles/Y.jav";
|
||||||
|
fileToTest = new File(path);
|
||||||
|
compiler = new JavaTXCompiler(fileToTest);
|
||||||
|
compiler.generateBytecode(System.getProperty("user.dir")+"/testBytecode/generatedBC/");
|
||||||
|
pathToClassFile = System.getProperty("user.dir")+"/testBytecode/generatedBC/";
|
||||||
|
loader = new URLClassLoader(new URL[] {new URL("file://"+pathToClassFile)});
|
||||||
|
classToTest = loader.loadClass("Y");
|
||||||
|
/*
|
||||||
|
instanceOfClass = classToTest.getDeclaredConstructor().newInstance();
|
||||||
|
|
||||||
|
Method m = classToTest.getDeclaredMethod("m");
|
||||||
|
Class<?> lambda = m.invoke(instanceOfClass).getClass();
|
||||||
|
Method apply = lambda.getMethod("apply", Object.class);
|
||||||
|
|
||||||
|
// Damit man auf die Methode zugreifen kann
|
||||||
|
apply.setAccessible(true);
|
||||||
|
|
||||||
|
Integer i = 77;
|
||||||
|
|
||||||
|
Integer result = (Integer) apply.invoke(m.invoke(instanceOfClass), i);
|
||||||
|
|
||||||
|
assertEquals(77, result);
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
9
test/bytecode/javFiles/Field.jav
Normal file
9
test/bytecode/javFiles/Field.jav
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import java.lang.Integer;
|
||||||
|
|
||||||
|
public class Field {
|
||||||
|
public Integer x = 5;
|
||||||
|
|
||||||
|
m(){
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,6 @@
|
|||||||
import java.util.Vector;
|
import java.util.Vector;
|
||||||
import java.lang.Integer;
|
import java.lang.Integer;
|
||||||
|
//import java.lang.Float;
|
||||||
//import java.lang.Byte;
|
//import java.lang.Byte;
|
||||||
import java.lang.Boolean;
|
import java.lang.Boolean;
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@ import java.util.List;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.lang.String;
|
import java.lang.String;
|
||||||
|
|
||||||
class Sorting{
|
public class Sorting{
|
||||||
merge(a, b){
|
merge(a, b){
|
||||||
a.addAll(b);
|
a.addAll(b);
|
||||||
return a;
|
return a;
|
||||||
|
@ -2,7 +2,7 @@ public class Tph {
|
|||||||
|
|
||||||
m(a,b){
|
m(a,b){
|
||||||
var c = m2(b);
|
var c = m2(b);
|
||||||
return c;
|
return a;
|
||||||
// return m2(b);
|
// return m2(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
28
test/bytecode/javFiles/Y.jav
Normal file
28
test/bytecode/javFiles/Y.jav
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
import java.lang.Integer;
|
||||||
|
|
||||||
|
class Y {
|
||||||
|
y;
|
||||||
|
//factorial;
|
||||||
|
|
||||||
|
Y() {
|
||||||
|
y = f -> t -> f.apply(y.apply(f)).apply(t);
|
||||||
|
//factorial = y.apply(f -> n -> { if (n == 0) return 1; else return n * f.apply(n - 1); });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
ergibt Parse-Error
|
||||||
|
class fac1 {
|
||||||
|
factorial;
|
||||||
|
|
||||||
|
fac1() {
|
||||||
|
var y;
|
||||||
|
y = new Y<>().y;
|
||||||
|
factorial = y.apply(f -> n -> { if (n == 0) return 1; else return n * f.apply(n - 1); });
|
||||||
|
}
|
||||||
|
public static void main(String args[]) {
|
||||||
|
System.out.println(new fac1().factorial.apply(3));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
*/
|
Loading…
Reference in New Issue
Block a user