diff --git a/src/de/dhbwstuttgart/bytecode/AStatement.java b/src/de/dhbwstuttgart/bytecode/AStatement.java new file mode 100644 index 00000000..5c28bf43 --- /dev/null +++ b/src/de/dhbwstuttgart/bytecode/AStatement.java @@ -0,0 +1,30 @@ +package de.dhbwstuttgart.bytecode; + +import org.objectweb.asm.Label; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; + +import de.dhbwstuttgart.syntaxtree.statement.BinaryExpr; +import de.dhbwstuttgart.syntaxtree.statement.Expression; + +public abstract class AStatement implements IStatement { + protected Expression expr; + + public AStatement(Expression expr) { + this.expr = expr; + } + + @Override + public boolean isExprBinary() { + return (expr instanceof BinaryExpr); + } + + @Override + public void genBCForRelOp(MethodVisitor mv,Label branchLabel, Label endLabel, BytecodeGenMethod bytecodeGenMethod) { + mv.visitInsn(Opcodes.ICONST_1); + mv.visitJumpInsn(Opcodes.GOTO, endLabel); + mv.visitLabel(branchLabel); + mv.visitInsn(Opcodes.ICONST_0); + mv.visitLabel(endLabel); + } +} diff --git a/src/de/dhbwstuttgart/bytecode/ArgumentExpr.java b/src/de/dhbwstuttgart/bytecode/ArgumentExpr.java new file mode 100644 index 00000000..b396e8d1 --- /dev/null +++ b/src/de/dhbwstuttgart/bytecode/ArgumentExpr.java @@ -0,0 +1,11 @@ +package de.dhbwstuttgart.bytecode; + +import de.dhbwstuttgart.syntaxtree.statement.Expression; + +public class ArgumentExpr extends AStatement { + + public ArgumentExpr(Expression expr) { + super(expr); + } + +} diff --git a/src/de/dhbwstuttgart/bytecode/AssignStmt.java b/src/de/dhbwstuttgart/bytecode/AssignStmt.java new file mode 100644 index 00000000..366c450a --- /dev/null +++ b/src/de/dhbwstuttgart/bytecode/AssignStmt.java @@ -0,0 +1,11 @@ +package de.dhbwstuttgart.bytecode; + +import de.dhbwstuttgart.syntaxtree.statement.Expression; + +public class AssignStmt extends AStatement { + + public AssignStmt(Expression rightSide) { + super(rightSide); + } + +} diff --git a/src/de/dhbwstuttgart/bytecode/BytecodeGen.java b/src/de/dhbwstuttgart/bytecode/BytecodeGen.java index 52feb6e5..f9bf72ed 100644 --- a/src/de/dhbwstuttgart/bytecode/BytecodeGen.java +++ b/src/de/dhbwstuttgart/bytecode/BytecodeGen.java @@ -17,6 +17,8 @@ import de.dhbwstuttgart.bytecode.descriptor.DescriptorToString; import de.dhbwstuttgart.bytecode.descriptor.TypeToDescriptor; import de.dhbwstuttgart.bytecode.signature.Signature; import de.dhbwstuttgart.bytecode.signature.TypeToString; +import de.dhbwstuttgart.bytecode.utilities.NormalConstructor; +import de.dhbwstuttgart.bytecode.utilities.NormalMethod; import de.dhbwstuttgart.parser.SyntaxTreeGenerator.AssignToLocal; import de.dhbwstuttgart.syntaxtree.*; import de.dhbwstuttgart.syntaxtree.statement.Literal; @@ -115,7 +117,7 @@ public class BytecodeGen implements ASTVisitor { boolean isConsWithNoParamsVisited = false; for(ResultSet rs : listOfResultSets) { resultSet = rs; - + for(Constructor c : classOrInterface.getConstructors()) { if(!isConsWithNoParamsVisited) c.accept(this); @@ -189,13 +191,13 @@ public class BytecodeGen implements ASTVisitor { System.out.println(acc); /*Prüfe, ob die Rückgabe-Type der Methode eine Type-Variable ist*/ - boolean hasGenInParameterList = genericsAndBounds.containsKey(resultSet.resolveType(method.getReturnType()).resolvedType.acceptTV(new TypeToDescriptor())); + boolean hasGenInParameterList = genericsAndBounds.containsKey(retType) || retType.subSequence(0, 4).equals("TPH "); /*Wenn die Rückgabe-Type eine Typ-variable ist, erzeuge direkt die Signature, wenn nicht, * prüfe, ob einer der Parameter Typ-Variable als Typ hat*/ if(!hasGenInParameterList) { for(String paramName : methodParamsAndTypes.keySet()) { String typeOfParam = methodParamsAndTypes.get(paramName).acceptTV(new TypeToDescriptor()); - if(genericsAndBounds.containsKey(typeOfParam)) { + if(genericsAndBounds.containsKey(typeOfParam)||typeOfParam.substring(0, 4).equals("TPH ")) { hasGenInParameterList = true; break; } @@ -211,6 +213,7 @@ public class BytecodeGen implements ASTVisitor { boolean hasGen = method.getGenerics().iterator().hasNext() || hasGenInParameterList; /* if method has generics or return type is TPH, create signature */ + // zwite operand muss weggelassen werden if(hasGen||method.getReturnType().acceptTV(new TypeToString()).equals("TPH")) { // resultset hier zum testen Signature signature = new Signature(method, genericsAndBoundsMethod, methodParamsAndTypes,resultSet); diff --git a/src/de/dhbwstuttgart/bytecode/BytecodeGenMethod.java b/src/de/dhbwstuttgart/bytecode/BytecodeGenMethod.java index ce5d3def..8bb7dca1 100644 --- a/src/de/dhbwstuttgart/bytecode/BytecodeGenMethod.java +++ b/src/de/dhbwstuttgart/bytecode/BytecodeGenMethod.java @@ -29,8 +29,10 @@ import org.objectweb.asm.signature.SignatureWriter; import de.dhbwstuttgart.bytecode.descriptor.DescriptorToString; import de.dhbwstuttgart.bytecode.descriptor.TypeToDescriptor; import de.dhbwstuttgart.bytecode.signature.Signature; -import de.dhbwstuttgart.bytecode.signature.TypeToSignature; -import de.dhbwstuttgart.bytecode.signature.TypeToString; +import de.dhbwstuttgart.bytecode.utilities.KindOfLambda; +import de.dhbwstuttgart.bytecode.utilities.Lambda; +import de.dhbwstuttgart.bytecode.utilities.MethodFromMethodCall; +import de.dhbwstuttgart.bytecode.utilities.SamMethod; import de.dhbwstuttgart.parser.SyntaxTreeGenerator.AssignToLocal; import de.dhbwstuttgart.syntaxtree.FormalParameter; import de.dhbwstuttgart.syntaxtree.Method; @@ -52,17 +54,16 @@ public class BytecodeGenMethod implements StatementVisitor { private HashMap genericsAndBounds; private boolean isBinaryExp = false; + private IStatement statement = null; + // for tests ** private String fieldName; private String fieldDesc; private Expression rightSideTemp; - + private boolean isRightSideALambda = false; private KindOfLambda kindOfLambda; private HashMap classFiles; - - private boolean isAssignStmt = false; - private Statement loopBlock; private ArrayList varsFunInterface = new ArrayList<>();; @@ -107,7 +108,7 @@ public class BytecodeGenMethod implements StatementVisitor { private String getResolvedType(RefTypeOrTPHOrWildcardOrGeneric type) { return resultSet.resolveType(type).resolvedType.acceptTV(new TypeToDescriptor()); } - + @Override public void visit(Block block) { for (Statement stmt : block.getStatements()) { @@ -132,7 +133,7 @@ public class BytecodeGenMethod implements StatementVisitor { mv.visitVarInsn(Opcodes.ALOAD, paramsAndLocals.get(localVar.name)); if (isBinaryExp) { - getVlaueIns(getResolvedType(localVar.getType())); + doUnboxing(getResolvedType(localVar.getType())); } } @@ -144,8 +145,7 @@ public class BytecodeGenMethod implements StatementVisitor { @Override public void visit(Assign assign) { - isAssignStmt = true; - + statement = new AssignStmt(assign.rightSide); // if the right side is a lambda => the left side must be a functional interface if (assign.rightSide instanceof LambdaExpression) { isRightSideALambda = true; @@ -153,9 +153,7 @@ public class BytecodeGenMethod implements StatementVisitor { isRightSideALambda = false; } - if (assign.rightSide instanceof BinaryExpr) - isBinaryExp = true; - + isBinaryExp = statement.isExprBinary(); if (assign.lefSide instanceof AssignToField) { // load_0, ldc or .. then putfield @@ -165,26 +163,24 @@ public class BytecodeGenMethod implements StatementVisitor { } if (isBinaryExp) { BinaryExpr binary = (BinaryExpr) assign.rightSide; - String lexpType = getResolvedType(binary.lexpr.getType()); - String rexpType = getResolvedType(binary.rexpr.getType()); - getValueOfIns(getLargerType(lexpType, rexpType)); + String binaryType = getResolvedType(binary.getType()); + doBoxing(binaryType); isBinaryExp = false; } assign.lefSide.accept(this); - - isAssignStmt =false; - } + statement = null; + } @Override public void visit(BinaryExpr binary) { - + String lexpType = getResolvedType(binary.lexpr.getType()); String rexpType = getResolvedType(binary.rexpr.getType()); - - String largerType = getLargerType(lexpType,rexpType); + + String largerType = getLargerType(lexpType, rexpType); String typeOfBinary = getResolvedType(binary.getType()); - + if (typeOfBinary.equals(Type.getInternalName(String.class))) { mv.visitTypeInsn(Opcodes.NEW, Type.getInternalName(StringBuilder.class)); mv.visitInsn(Opcodes.DUP); @@ -194,23 +190,21 @@ public class BytecodeGenMethod implements StatementVisitor { Label endLabel = new Label(); // this case for while loops - if(!isAssignStmt) + if (statement instanceof LoopStmt) mv.visitLabel(endLabel); - + binary.lexpr.accept(this); - - if(!lexpType.equals(rexpType) && - !lexpType.equals(largerType)) + + if (!lexpType.equals(rexpType) && !lexpType.equals(largerType)) doCast(lexpType, largerType); - + binary.rexpr.accept(this); - - if(!lexpType.equals(rexpType) && - !rexpType.equals(largerType)) + + if (!lexpType.equals(rexpType) && !rexpType.equals(largerType)) doCast(rexpType, largerType); - + Operator op = binary.operation; - + switch (op) { case ADD: doVisitAddOpInsn(largerType); @@ -237,28 +231,31 @@ public class BytecodeGenMethod implements StatementVisitor { case BIGGERTHAN: case BIGGEREQUAL: Label branchLabel = new Label(); - doVisitRelOpInsn(op,largerType, branchLabel, endLabel); + doVisitRelOpInsn(op, largerType, branchLabel, endLabel); break; - + default: break; } } + /* + * Diese Methode wird nicht mehr gebraucht, da es jetzt nicht möglich ist, dass + * solche Fälle: Integer -> Integer (OP) Short ,... usw, nicht vorkommen! + */ private String getLargerType(String lexpType, String rexpType) { - if(lexpType.equals(Type.getInternalName(String.class)) || - rexpType.equals(Type.getInternalName(String.class))) { + if (lexpType.equals(Type.getInternalName(String.class)) + || rexpType.equals(Type.getInternalName(String.class))) { return Type.getInternalName(String.class); - } else - if(lexpType.equals(Type.getInternalName(Double.class)) || - rexpType.equals(Type.getInternalName(Double.class))) { + } else if (lexpType.equals(Type.getInternalName(Double.class)) + || rexpType.equals(Type.getInternalName(Double.class))) { return Type.getInternalName(Double.class); - } else if(lexpType.equals(Type.getInternalName(Float.class)) || - rexpType.equals(Type.getInternalName(Float.class))) { + } else if (lexpType.equals(Type.getInternalName(Float.class)) + || rexpType.equals(Type.getInternalName(Float.class))) { return Type.getInternalName(Float.class); - } else if(lexpType.equals(Type.getInternalName(Long.class)) || - rexpType.equals(Type.getInternalName(Long.class))) { + } else if (lexpType.equals(Type.getInternalName(Long.class)) + || rexpType.equals(Type.getInternalName(Long.class))) { return Type.getInternalName(Long.class); } else { return Type.getInternalName(Integer.class); @@ -270,19 +267,19 @@ public class BytecodeGenMethod implements StatementVisitor { case "java/lang/Long": mv.visitInsn(Opcodes.I2L); break; - + case "java/lang/Double": - if(sourceType.equals(Type.getInternalName(Long.class))) { + if (sourceType.equals(Type.getInternalName(Long.class))) { mv.visitInsn(Opcodes.L2D); - } else if(sourceType.equals(Type.getInternalName(Float.class))) { + } else if (sourceType.equals(Type.getInternalName(Float.class))) { mv.visitInsn(Opcodes.F2D); } else { mv.visitInsn(Opcodes.I2D); } break; - + case "java/lang/Float": - if(sourceType.equals(Type.getInternalName(Long.class))) { + if (sourceType.equals(Type.getInternalName(Long.class))) { mv.visitInsn(Opcodes.L2F); } else { mv.visitInsn(Opcodes.I2F); @@ -290,14 +287,18 @@ public class BytecodeGenMethod implements StatementVisitor { break; // braucht man eigentlic nicht, muss getestet werden case "java/lang/String": - if(sourceType.equals(Type.getInternalName(Double.class))) { - mv.visitMethodInsn(Opcodes.INVOKESTATIC, Type.getInternalName(String.class), "valueOf", "(D)Ljava/lang/String;", false); - } else if(sourceType.equals(Type.getInternalName(Long.class))) { - mv.visitMethodInsn(Opcodes.INVOKESTATIC, Type.getInternalName(String.class), "valueOf", "(J)Ljava/lang/String;", false); - } else if(sourceType.equals(Type.getInternalName(Float.class))) { - mv.visitMethodInsn(Opcodes.INVOKESTATIC, Type.getInternalName(String.class), "valueOf", "(F)Ljava/lang/String;", false); + if (sourceType.equals(Type.getInternalName(Double.class))) { + mv.visitMethodInsn(Opcodes.INVOKESTATIC, Type.getInternalName(String.class), "valueOf", + "(D)Ljava/lang/String;", false); + } else if (sourceType.equals(Type.getInternalName(Long.class))) { + mv.visitMethodInsn(Opcodes.INVOKESTATIC, Type.getInternalName(String.class), "valueOf", + "(J)Ljava/lang/String;", false); + } else if (sourceType.equals(Type.getInternalName(Float.class))) { + mv.visitMethodInsn(Opcodes.INVOKESTATIC, Type.getInternalName(String.class), "valueOf", + "(F)Ljava/lang/String;", false); } else { - mv.visitMethodInsn(Opcodes.INVOKESTATIC, Type.getInternalName(String.class), "valueOf", "(I)Ljava/lang/String;", false); + mv.visitMethodInsn(Opcodes.INVOKESTATIC, Type.getInternalName(String.class), "valueOf", + "(I)Ljava/lang/String;", false); } break; default: @@ -306,7 +307,7 @@ public class BytecodeGenMethod implements StatementVisitor { } private void doVisitRelOpInsn(Operator op, String typeOfBinary, Label branchLabel, Label endLabel) { - + switch (typeOfBinary) { case "java/lang/Long": mv.visitInsn(Opcodes.LCMP); @@ -337,18 +338,9 @@ public class BytecodeGenMethod implements StatementVisitor { default: break; } - if(isAssignStmt) { - mv.visitInsn(Opcodes.ICONST_1); - mv.visitJumpInsn(Opcodes.GOTO, endLabel); - mv.visitLabel(branchLabel); - mv.visitInsn(Opcodes.ICONST_0); - mv.visitLabel(endLabel); - } else { - loopBlock.accept(this); - mv.visitJumpInsn(Opcodes.GOTO, endLabel); - - mv.visitLabel(branchLabel); - } + + statement.genBCForRelOp(mv, branchLabel, endLabel, this); + break; } } @@ -371,19 +363,8 @@ public class BytecodeGenMethod implements StatementVisitor { default: break; } - if(isAssignStmt) { - mv.visitInsn(Opcodes.ICONST_1); - mv.visitJumpInsn(Opcodes.GOTO, endLabel); - mv.visitLabel(branchLabel); - mv.visitInsn(Opcodes.ICONST_0); - mv.visitLabel(endLabel); - } else { - loopBlock.accept(this); - mv.visitJumpInsn(Opcodes.GOTO, endLabel); - - mv.visitLabel(branchLabel); - } - + + statement.genBCForRelOp(mv, branchLabel, endLabel, this); } private void doVisitModOpInsn(String typeOfBinary) { @@ -546,7 +527,7 @@ public class BytecodeGenMethod implements StatementVisitor { cw.visitInnerClass("java/lang/invoke/MethodHandles$Lookup", "java/lang/invoke/MethodHandles", "Lookup", Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC + Opcodes.ACC_FINAL); - generateBCForFunN(lambdaExpression,typeErasure); + generateBCForFunN(lambdaExpression, typeErasure); } private void generateBCForFunN(LambdaExpression lambdaExpression, String methDesc) { @@ -566,7 +547,7 @@ public class BytecodeGenMethod implements StatementVisitor { methSig.visitReturnType().visitTypeVariable("R"); // ")"+lam.getReturn.getBounds Signature sig = new Signature(lambdaExpression, numberOfParams); - String name = "Fun" + numberOfParams; + String name = "Fun" + numberOfParams + "$$"; classWriter.visit(Opcodes.V1_8, Opcodes.ACC_INTERFACE + Opcodes.ACC_ABSTRACT, name, sig.toString(), Type.getInternalName(Object.class), null); MethodVisitor mvApply = classWriter.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_ABSTRACT, "apply", methDesc, @@ -640,6 +621,7 @@ public class BytecodeGenMethod implements StatementVisitor { @Override public void visit(MethodCall methodCall) { + methodCall.receiver.accept(this); methodCall.arglist.accept(this); @@ -647,7 +629,7 @@ public class BytecodeGenMethod implements StatementVisitor { genericsAndBoundsMethod, genericsAndBounds); String mDesc = method.accept(new DescriptorToString(resultSet)); - // is methodCall.receiver functional Interface)? + // is methodCall.receiver functional Interface)? if (varsFunInterface.contains(methodCall.receiver.getType())) { mv.visitMethodInsn(Opcodes.INVOKEINTERFACE, getResolvedType(methodCall.receiver.getType()), methodCall.name, mDesc, false); @@ -692,40 +674,40 @@ public class BytecodeGenMethod implements StatementVisitor { public void visit(UnaryExpr unaryExpr) { unaryExpr.expr.accept(this); Operation op = unaryExpr.operation; - + String typeOfUnary = getResolvedType(unaryExpr.getType()); - + boolean isIncOrDec = false; - + switch (op) { case POSTDECREMENT: case POSTINCREMENT: - if(isAssignStmt) + if (statement instanceof AssignStmt) mv.visitInsn(Opcodes.DUP); genBCForIncAndDec(op, typeOfUnary); - getValueOfIns(typeOfUnary); + doBoxing(typeOfUnary); isIncOrDec = true; break; case PREDECREMENT: case PREINCREMENT: genBCForIncAndDec(op, typeOfUnary); - getValueOfIns(typeOfUnary); - if(isAssignStmt) + doBoxing(typeOfUnary); + if (statement instanceof AssignStmt) mv.visitInsn(Opcodes.DUP); isIncOrDec = true; break; - + case MINUS: doVisitNegIns(typeOfUnary); break; default: break; } - + // Für Byte und Short muss noch einen Cast geben i2b, i2s // das wird später gemacht, da bytecode für cast noch nicht erzeugt wird - - if(isIncOrDec && (unaryExpr.expr instanceof LocalVar)) { + + if (isIncOrDec && (unaryExpr.expr instanceof LocalVar)) { LocalVar local = (LocalVar) unaryExpr.expr; mv.visitVarInsn(Opcodes.ASTORE, paramsAndLocals.get(local.name)); } @@ -746,14 +728,14 @@ public class BytecodeGenMethod implements StatementVisitor { mv.visitInsn(Opcodes.INEG); break; } - + } private void genBCForIncAndDec(Operation op, String typeOfUnary) { - - getVlaueIns(typeOfUnary); - doAssign(typeOfUnary, 1.0, true); - + + doUnboxing(typeOfUnary); + loadValue(typeOfUnary, 1.0, true); + switch (op) { case POSTDECREMENT: case PREDECREMENT: @@ -764,7 +746,7 @@ public class BytecodeGenMethod implements StatementVisitor { case PREINCREMENT: doVisitAddOpInsn(typeOfUnary); break; - + default: break; } @@ -772,20 +754,19 @@ public class BytecodeGenMethod implements StatementVisitor { @Override public void visit(Return aReturn) { - if(aReturn.retexpr instanceof BinaryExpr) - isBinaryExp = true; - + statement = new ReturnStmt(aReturn.retexpr); + isBinaryExp = statement.isExprBinary(); + aReturn.retexpr.accept(this); - + if (isBinaryExp) { BinaryExpr binary = (BinaryExpr) aReturn.retexpr; - String lexpType = getResolvedType(binary.lexpr.getType()); - String rexpType = getResolvedType(binary.rexpr.getType()); - getValueOfIns(getLargerType(lexpType, rexpType)); + doBoxing(getResolvedType(binary.getType())); isBinaryExp = false; } - + mv.visitInsn(Opcodes.ARETURN); + statement = null; } @Override @@ -798,7 +779,8 @@ public class BytecodeGenMethod implements StatementVisitor { // mv.visitMethodInsn(Opcodes.INVOKESTATIC, // staticClassName.getType().toString().replace(".", "/"), // staticClassName.toString(), staticClassName.getType().toString(), false); - //mv.visitFieldInsn(Opcodes.GETSTATIC, getResolvedType(staticClassName.getType()), fieldName, fieldDesc); + // mv.visitFieldInsn(Opcodes.GETSTATIC, + // getResolvedType(staticClassName.getType()), fieldName, fieldDesc); throw new NotImplementedException("Static noch nicht implementiert!"); } @@ -814,14 +796,11 @@ public class BytecodeGenMethod implements StatementVisitor { @Override public void visit(WhileStmt whileStmt) { - this.loopBlock = whileStmt.loopBlock; - - if(whileStmt.expr instanceof BinaryExpr) - isBinaryExp = true; - + statement = new LoopStmt(whileStmt.expr, whileStmt.loopBlock); + isBinaryExp = statement.isExprBinary(); whileStmt.expr.accept(this); - isBinaryExp = false; + statement = null; } @Override @@ -834,12 +813,13 @@ public class BytecodeGenMethod implements StatementVisitor { public void visit(Literal literal) { Object value = literal.value; String typeOfLiteral = getResolvedType(literal.getType()); - // Name der Methode muss geändert werden - doAssign(typeOfLiteral, value, false); - + // Der Wert des Literals wird auf den Stack geladen und + // geboxt, wenn es nötig ist. + loadValue(typeOfLiteral, value, false); } - private void getVlaueIns(String type) { + // Unboxing: RefType -> prim + private void doUnboxing(String type) { switch (type) { case "java/lang/String": mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, Type.getInternalName(StringBuilder.class), "append", @@ -869,11 +849,13 @@ public class BytecodeGenMethod implements StatementVisitor { case "java/lang/Character": break; default: + // mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Integer", "intValue", + // "()I", false); break; } } - private void doAssign(String type, Object value, boolean isOperator) { + private void loadValue(String type, Object value, boolean isOperator) { switch (type) { case "java/lang/String": mv.visitLdcInsn(String.valueOf(value)); @@ -904,17 +886,21 @@ public class BytecodeGenMethod implements StatementVisitor { visitCharLiteral((Character) value); break; default: + // wenn die Typ des Literals = Number ist, wird integer-value + // verwendet + // visitIntegerLiteral(((Double) value).intValue(), false); break; } - - if(!type.equals("java/lang/String")&&!type.equals("java/lang/Boolean")) { + // Boxing + if (!type.equals("java/lang/String") && !type.equals("java/lang/Boolean")) { if (!this.isBinaryExp && !isOperator) - getValueOfIns(type); + doBoxing(type); } - + } - private void getValueOfIns(String type) { + // Boxing: prim -> RefType + private void doBoxing(String type) { switch (type) { case "java/lang/String": mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/StringBuilder", "toString", "()Ljava/lang/String;", @@ -952,7 +938,7 @@ public class BytecodeGenMethod implements StatementVisitor { private void visitCharLiteral(Character value) { mv.visitIntInsn(Opcodes.BIPUSH, (int) value); - + } private void visitDoubleLiteral(Double value) { @@ -1026,7 +1012,9 @@ public class BytecodeGenMethod implements StatementVisitor { @Override public void visit(ArgumentList argumentList) { for (Expression al : argumentList.getArguments()) { + statement = new ArgumentExpr(al); al.accept(this); + statement = null; } } @@ -1050,12 +1038,12 @@ public class BytecodeGenMethod implements StatementVisitor { varsFunInterface.add(assignLeftSide.localVar.getType()); int index = paramsAndLocals.size(); String var = assignLeftSide.localVar.name; - if(!paramsAndLocals.containsKey(var)) { + if (!paramsAndLocals.containsKey(var)) { paramsAndLocals.put(var, index + 1); - }else { + } else { paramsAndLocals.put(var, index); } - + mv.visitVarInsn(Opcodes.ASTORE, paramsAndLocals.size()); // Debug::: diff --git a/src/de/dhbwstuttgart/bytecode/IStatement.java b/src/de/dhbwstuttgart/bytecode/IStatement.java new file mode 100644 index 00000000..f8d61097 --- /dev/null +++ b/src/de/dhbwstuttgart/bytecode/IStatement.java @@ -0,0 +1,9 @@ +package de.dhbwstuttgart.bytecode; + +import org.objectweb.asm.Label; +import org.objectweb.asm.MethodVisitor; + +public interface IStatement { + public boolean isExprBinary(); + public void genBCForRelOp(MethodVisitor mv, Label branchLabel, Label endLabel, BytecodeGenMethod bytecodeGenMethod); +} diff --git a/src/de/dhbwstuttgart/bytecode/LoopStmt.java b/src/de/dhbwstuttgart/bytecode/LoopStmt.java new file mode 100644 index 00000000..109efd34 --- /dev/null +++ b/src/de/dhbwstuttgart/bytecode/LoopStmt.java @@ -0,0 +1,25 @@ +package de.dhbwstuttgart.bytecode; + +import org.objectweb.asm.Label; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; + +import de.dhbwstuttgart.syntaxtree.statement.Expression; +import de.dhbwstuttgart.syntaxtree.statement.Statement; + +public class LoopStmt extends AStatement { + + private Statement loopBlock; + + public LoopStmt(Expression expr, Statement loopBlock) { + super(expr); + this.loopBlock = loopBlock; + } + + @Override + public void genBCForRelOp(MethodVisitor mv,Label branchLabel, Label endLabel, BytecodeGenMethod bytecodeGenMethod) { + this.loopBlock.accept(bytecodeGenMethod); + mv.visitJumpInsn(Opcodes.GOTO, endLabel); + mv.visitLabel(branchLabel); + } +} diff --git a/src/de/dhbwstuttgart/bytecode/ReturnStmt.java b/src/de/dhbwstuttgart/bytecode/ReturnStmt.java new file mode 100644 index 00000000..bd747720 --- /dev/null +++ b/src/de/dhbwstuttgart/bytecode/ReturnStmt.java @@ -0,0 +1,14 @@ +package de.dhbwstuttgart.bytecode; + +import org.objectweb.asm.MethodVisitor; + +import de.dhbwstuttgart.syntaxtree.statement.BinaryExpr; +import de.dhbwstuttgart.syntaxtree.statement.Expression; + +public class ReturnStmt extends AStatement { + + public ReturnStmt(Expression retexpr) { + super(retexpr); + } + +} diff --git a/src/de/dhbwstuttgart/bytecode/descriptor/DescriptorToString.java b/src/de/dhbwstuttgart/bytecode/descriptor/DescriptorToString.java index 65f48f71..0e97ca4c 100644 --- a/src/de/dhbwstuttgart/bytecode/descriptor/DescriptorToString.java +++ b/src/de/dhbwstuttgart/bytecode/descriptor/DescriptorToString.java @@ -2,12 +2,12 @@ package de.dhbwstuttgart.bytecode.descriptor; import java.util.Iterator; -import de.dhbwstuttgart.bytecode.Lambda; -import de.dhbwstuttgart.bytecode.MethodFromMethodCall; -import de.dhbwstuttgart.bytecode.NormalConstructor; -import de.dhbwstuttgart.bytecode.NormalMethod; -import de.dhbwstuttgart.bytecode.SamMethod; import de.dhbwstuttgart.bytecode.signature.TypeToSignature; +import de.dhbwstuttgart.bytecode.utilities.Lambda; +import de.dhbwstuttgart.bytecode.utilities.MethodFromMethodCall; +import de.dhbwstuttgart.bytecode.utilities.NormalConstructor; +import de.dhbwstuttgart.bytecode.utilities.NormalMethod; +import de.dhbwstuttgart.bytecode.utilities.SamMethod; import de.dhbwstuttgart.syntaxtree.FormalParameter; import de.dhbwstuttgart.syntaxtree.statement.Expression; import de.dhbwstuttgart.syntaxtree.type.RefType; @@ -46,12 +46,18 @@ public class DescriptorToString implements DescriptorVisitor{ }else if(method.getGenericsAndBounds().containsKey(fpDesc)){ desc += "L"+method.getGenericsAndBounds().get(fpDesc)+ ";"; }else { - desc += "L"+resultSet.resolveType(fp.getType()).resolvedType.acceptTV(new TypeToDescriptor())+ ";"; +// desc += "L"+resultSet.resolveType(fp.getType()).resolvedType.acceptTV(new TypeToDescriptor())+ ";"; + String resType = resultSet.resolveType(fp.getType()).resolvedType.acceptTV(new TypeToDescriptor()); + if(resType.subSequence(0, 4).equals("TPH ")) { + desc += "L"+method.getGenericsAndBoundsMethod().get(resType.substring(4)+"$")+ ";"; + } else { + desc += "L"+resType+ ";"; + } } } //TODO: generate a class java%% ... %% else if(resultSet.resolveType(fp.getType()).resolvedType.acceptTV(new TypeToDescriptor()).contains("<")){ - desc += "L"+resultSet.resolveType(fp.getType()).resolvedType.toString().replace(".", "%").replace("<", "%%").replace(">", "%%")+ ";"; + desc += "L"+resultSet.resolveType(fp.getType()).resolvedType.toString().replace(".", "$$").replace("<", "$$$").replace(">", "$$$")+ ";"; } else { desc += "L"+resultSet.resolveType(fp.getType()).resolvedType.acceptTV(new TypeToDescriptor())+ ";"; @@ -68,7 +74,12 @@ public class DescriptorToString implements DescriptorVisitor{ }else if(method.getGenericsAndBounds().containsKey(ret)){ desc += ")L"+method.getGenericsAndBounds().get(ret)+ ";"; }else { - desc += ")" + "L"+resultSet.resolveType(method.getReturnType()).resolvedType.acceptTV(new TypeToDescriptor())+ ";"; + String resType = resultSet.resolveType(method.getReturnType()).resolvedType.acceptTV(new TypeToDescriptor()); + if(resType.subSequence(0, 4).equals("TPH ")) { + desc += ")" + "L"+method.getGenericsAndBoundsMethod().get(resType.substring(4)+"$")+ ";"; + } else { + desc += ")" + "L"+resType+ ";"; + } } }else { desc += ")" + "L"+resultSet.resolveType(method.getReturnType()).resolvedType.acceptTV(new TypeToDescriptor())+ ";"; diff --git a/src/de/dhbwstuttgart/bytecode/descriptor/DescriptorVisitor.java b/src/de/dhbwstuttgart/bytecode/descriptor/DescriptorVisitor.java index 6bc57f21..35f1423e 100644 --- a/src/de/dhbwstuttgart/bytecode/descriptor/DescriptorVisitor.java +++ b/src/de/dhbwstuttgart/bytecode/descriptor/DescriptorVisitor.java @@ -1,10 +1,10 @@ package de.dhbwstuttgart.bytecode.descriptor; -import de.dhbwstuttgart.bytecode.Lambda; -import de.dhbwstuttgart.bytecode.MethodFromMethodCall; -import de.dhbwstuttgart.bytecode.NormalConstructor; -import de.dhbwstuttgart.bytecode.NormalMethod; -import de.dhbwstuttgart.bytecode.SamMethod; +import de.dhbwstuttgart.bytecode.utilities.Lambda; +import de.dhbwstuttgart.bytecode.utilities.MethodFromMethodCall; +import de.dhbwstuttgart.bytecode.utilities.NormalConstructor; +import de.dhbwstuttgart.bytecode.utilities.NormalMethod; +import de.dhbwstuttgart.bytecode.utilities.SamMethod; public interface DescriptorVisitor { public String visit(NormalMethod method); diff --git a/src/de/dhbwstuttgart/bytecode/descriptor/TypeToDescriptor.java b/src/de/dhbwstuttgart/bytecode/descriptor/TypeToDescriptor.java index e374bb93..e5c853b3 100644 --- a/src/de/dhbwstuttgart/bytecode/descriptor/TypeToDescriptor.java +++ b/src/de/dhbwstuttgart/bytecode/descriptor/TypeToDescriptor.java @@ -13,6 +13,8 @@ public class TypeToDescriptor implements TypeVisitor{ @Override public String visit(RefType refType) { return refType.getName().toString().replace(".", "/"); +// String t = refType.getName().toString().replace(".", "/"); +// return t.equals("Fun1")?(t+"$$"):t; } @Override @@ -27,7 +29,8 @@ public class TypeToDescriptor implements TypeVisitor{ @Override public String visit(ExtendsWildcardType extendsWildcardType) { - throw new NotImplementedException(); + return extendsWildcardType.getInnerType().toString(); + //throw new NotImplementedException(); } @Override diff --git a/src/de/dhbwstuttgart/bytecode/signature/Signature.java b/src/de/dhbwstuttgart/bytecode/signature/Signature.java index 46202cb1..48804661 100644 --- a/src/de/dhbwstuttgart/bytecode/signature/Signature.java +++ b/src/de/dhbwstuttgart/bytecode/signature/Signature.java @@ -59,10 +59,7 @@ public class Signature { private void createSignatureForFunN(LambdaExpression lambdaExpression, int numberOfParams) { - sw.visitFormalTypeParameter("R"); - // getBounds vom Return-Type - sw.visitClassBound().visitClassType(Type.getInternalName(Object.class)); - sw.visitClassBound().visitEnd(); +// sw.visitClassBound().visitEnd(); for(int i = 0;i wird eine Formal Type Parameter K$ erzeugt und Bound = Object + String ret = resultSet.resolveType(method.getReturnType()).resolvedType.acceptTV(new TypeToSignature()); + if(ret.substring(0,4).equals("TPH ")) { + String g = ret.substring(4)+"$"; + sw.visitFormalTypeParameter(g); + sw.visitClassBound().visitClassType(Type.getInternalName(Object.class)); + genericsAndBoundsMethod.put(g, Type.getInternalName(Object.class)); + sw.visitClassBound().visitEnd(); + } + + for(String paramName : methodParamsAndTypes.keySet()) { + RefTypeOrTPHOrWildcardOrGeneric t = methodParamsAndTypes.get(paramName); + String pT = t.acceptTV(new TypeToSignature()); + // S.o + if(pT.substring(0,4).equals("TPH ") && !genericsAndBoundsMethod.containsKey(pT)) { + String gP = pT.substring(4)+"$"; + sw.visitFormalTypeParameter(gP); + sw.visitClassBound().visitClassType(Type.getInternalName(Object.class)); + genericsAndBoundsMethod.put(gP, Type.getInternalName(Object.class)); + sw.visitClassBound().visitEnd(); + } + } + + // visit each method-parameter to create the signature for(String paramName : methodParamsAndTypes.keySet()) { RefTypeOrTPHOrWildcardOrGeneric t = methodParamsAndTypes.get(paramName); // parameter type deswegen ist true @@ -99,6 +125,15 @@ public class Signature { if(isConstructor) { sw.visitReturnType().visitBaseType('V'); }else { +// String ret = resultSet.resolveType(method.getReturnType()).resolvedType.acceptTV(new TypeToSignature()); +// if(ret.substring(0,4).equals("TPH ")) { +// String g = ret.substring(4); +// if(!genericsAndBoundsMethod.containsKey(g)) { +// genericsAndBoundsMethod.put(g, Type.getInternalName(Object.class)); +// } else { +// genericsAndBoundsMethod.put(g+"_", Type.getInternalName(Object.class)); +// } +// } RefTypeOrTPHOrWildcardOrGeneric returnType = method.getReturnType(); // return type deswegen ist false doVisitParamsOrReturn(returnType, false); @@ -130,10 +165,16 @@ public class Signature { break; case "TPH": RefTypeOrTPHOrWildcardOrGeneric r = resultSet.resolveType(t).resolvedType; - if(!r.acceptTV(new TypeToSignature()).substring(0, 4).equals("TPH ")) - sv.visitInterface().visitClassType(r.acceptTV(new TypeToSignature())); -// sv.visitClassType(r.acceptTV(new TypeToSignature())); - System.out.println(r.getClass()+" Signature TPH: "+r.acceptTV(new TypeToSignature())); + // der Fall wenn die Type eine Interface ist, muss betrachtet werden + // Deswegen muss in ResutSet noch enthalten werden, ob die Type eine + // Interface oder eine Klasse ist. + if(!r.acceptTV(new TypeToSignature()).substring(0, 4).equals("TPH ")) { +// sv.visitInterface().visitClassType(r.acceptTV(new TypeToSignature())); + sv.visitClassType(r.acceptTV(new TypeToSignature())); + } else { + System.out.println(r.getClass()+" Signature TPH: "+r.acceptTV(new TypeToSignature())); + sv.visitTypeVariable(r.acceptTV(new TypeToSignature()).substring(4)+"$"); + } break; default: if(!isParameterType) diff --git a/src/de/dhbwstuttgart/bytecode/signature/TypeToSignature.java b/src/de/dhbwstuttgart/bytecode/signature/TypeToSignature.java index 78b2fb22..a1357d4c 100644 --- a/src/de/dhbwstuttgart/bytecode/signature/TypeToSignature.java +++ b/src/de/dhbwstuttgart/bytecode/signature/TypeToSignature.java @@ -27,6 +27,8 @@ public class TypeToSignature implements TypeVisitor { } params += ";>"; } +// String t = refType.getName().toString().replace(".", "/"); +// return t.equals("Fun1")?t+"$$"+params+";":t+params+";"; return refType.getName().toString().replace(".", "/") + params+";"; } diff --git a/src/de/dhbwstuttgart/bytecode/KindOfLambda.java b/src/de/dhbwstuttgart/bytecode/utilities/KindOfLambda.java similarity index 98% rename from src/de/dhbwstuttgart/bytecode/KindOfLambda.java rename to src/de/dhbwstuttgart/bytecode/utilities/KindOfLambda.java index 1cc8e386..d2f7ee5b 100644 --- a/src/de/dhbwstuttgart/bytecode/KindOfLambda.java +++ b/src/de/dhbwstuttgart/bytecode/utilities/KindOfLambda.java @@ -1,4 +1,4 @@ -package de.dhbwstuttgart.bytecode; +package de.dhbwstuttgart.bytecode.utilities; import de.dhbwstuttgart.exceptions.NotImplementedException; import de.dhbwstuttgart.syntaxtree.statement.*; diff --git a/src/de/dhbwstuttgart/bytecode/Lambda.java b/src/de/dhbwstuttgart/bytecode/utilities/Lambda.java similarity index 93% rename from src/de/dhbwstuttgart/bytecode/Lambda.java rename to src/de/dhbwstuttgart/bytecode/utilities/Lambda.java index c3b4e8f5..6371c618 100644 --- a/src/de/dhbwstuttgart/bytecode/Lambda.java +++ b/src/de/dhbwstuttgart/bytecode/utilities/Lambda.java @@ -1,4 +1,4 @@ -package de.dhbwstuttgart.bytecode; +package de.dhbwstuttgart.bytecode.utilities; import de.dhbwstuttgart.bytecode.descriptor.DescriptorVisitor; import de.dhbwstuttgart.syntaxtree.ParameterList; diff --git a/src/de/dhbwstuttgart/bytecode/MethodFromMethodCall.java b/src/de/dhbwstuttgart/bytecode/utilities/MethodFromMethodCall.java similarity index 96% rename from src/de/dhbwstuttgart/bytecode/MethodFromMethodCall.java rename to src/de/dhbwstuttgart/bytecode/utilities/MethodFromMethodCall.java index 0f781b46..cd8f5372 100644 --- a/src/de/dhbwstuttgart/bytecode/MethodFromMethodCall.java +++ b/src/de/dhbwstuttgart/bytecode/utilities/MethodFromMethodCall.java @@ -1,4 +1,4 @@ -package de.dhbwstuttgart.bytecode; +package de.dhbwstuttgart.bytecode.utilities; import java.util.HashMap; diff --git a/src/de/dhbwstuttgart/bytecode/NormalConstructor.java b/src/de/dhbwstuttgart/bytecode/utilities/NormalConstructor.java similarity index 95% rename from src/de/dhbwstuttgart/bytecode/NormalConstructor.java rename to src/de/dhbwstuttgart/bytecode/utilities/NormalConstructor.java index a9aa482a..3a16fb00 100644 --- a/src/de/dhbwstuttgart/bytecode/NormalConstructor.java +++ b/src/de/dhbwstuttgart/bytecode/utilities/NormalConstructor.java @@ -1,4 +1,4 @@ -package de.dhbwstuttgart.bytecode; +package de.dhbwstuttgart.bytecode.utilities; import java.util.HashMap; diff --git a/src/de/dhbwstuttgart/bytecode/NormalMethod.java b/src/de/dhbwstuttgart/bytecode/utilities/NormalMethod.java similarity index 97% rename from src/de/dhbwstuttgart/bytecode/NormalMethod.java rename to src/de/dhbwstuttgart/bytecode/utilities/NormalMethod.java index 5afc31fb..4e5bc887 100644 --- a/src/de/dhbwstuttgart/bytecode/NormalMethod.java +++ b/src/de/dhbwstuttgart/bytecode/utilities/NormalMethod.java @@ -1,4 +1,4 @@ -package de.dhbwstuttgart.bytecode; +package de.dhbwstuttgart.bytecode.utilities; import java.util.HashMap; diff --git a/src/de/dhbwstuttgart/bytecode/SamMethod.java b/src/de/dhbwstuttgart/bytecode/utilities/SamMethod.java similarity index 94% rename from src/de/dhbwstuttgart/bytecode/SamMethod.java rename to src/de/dhbwstuttgart/bytecode/utilities/SamMethod.java index f14d5407..1c1b883c 100644 --- a/src/de/dhbwstuttgart/bytecode/SamMethod.java +++ b/src/de/dhbwstuttgart/bytecode/utilities/SamMethod.java @@ -1,4 +1,4 @@ -package de.dhbwstuttgart.bytecode; +package de.dhbwstuttgart.bytecode.utilities; import java.util.List; diff --git a/src/de/dhbwstuttgart/core/JavaTXCompiler.java b/src/de/dhbwstuttgart/core/JavaTXCompiler.java index ec74f0da..68bb2585 100644 --- a/src/de/dhbwstuttgart/core/JavaTXCompiler.java +++ b/src/de/dhbwstuttgart/core/JavaTXCompiler.java @@ -4,31 +4,38 @@ package de.dhbwstuttgart.core; import de.dhbwstuttgart.bytecode.BytecodeGen; import de.dhbwstuttgart.environment.CompilationEnvironment; import de.dhbwstuttgart.parser.JavaTXParser; +import de.dhbwstuttgart.parser.NullToken; import de.dhbwstuttgart.parser.scope.GenericsRegistry; import de.dhbwstuttgart.parser.SyntaxTreeGenerator.SyntaxTreeGenerator; import de.dhbwstuttgart.parser.antlr.Java8Parser.CompilationUnitContext; import de.dhbwstuttgart.parser.scope.JavaClassName; import de.dhbwstuttgart.parser.scope.JavaClassRegistry; import de.dhbwstuttgart.syntaxtree.ClassOrInterface; +import de.dhbwstuttgart.syntaxtree.ParameterList; import de.dhbwstuttgart.syntaxtree.SourceFile; import de.dhbwstuttgart.syntaxtree.factory.ASTFactory; import de.dhbwstuttgart.syntaxtree.factory.UnifyTypeFactory; import de.dhbwstuttgart.syntaxtree.type.TypePlaceholder; +import de.dhbwstuttgart.syntaxtree.visual.ASTTypePrinter; 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.model.FiniteClosure; +import de.dhbwstuttgart.typeinference.unify.model.PlaceholderType; import de.dhbwstuttgart.typeinference.unify.model.UnifyPair; import java.io.File; -import java.io.FileNotFoundException; import java.io.FileOutputStream; +import java.io.FileWriter; import java.io.IOException; import java.util.*; import java.util.stream.Collectors; +import java.util.stream.Stream; public class JavaTXCompiler { @@ -97,20 +104,114 @@ public class JavaTXCompiler { TypeUnify unify = new TypeUnify(); Set> results = new HashSet<>(); - for (List> xCons : unifyCons.cartesianProduct()) { - Set xConsSet = new HashSet<>(); - for (Constraint constraint : xCons) { - xConsSet.addAll(constraint); - } - - System.out.println(xConsSet); - Set> result = unify.unify(xConsSet, finiteClosure); - System.out.println("RESULT: " + result.size()); - results.addAll(result); + try { + FileWriter logFile = new FileWriter(new File(System.getProperty("user.dir")+"/test/logFiles/"+"log")); + logFile.write("FC:\\" + finiteClosure.toString()+"\n"); + for(SourceFile sf : this.sourceFiles.values()) { + logFile.write(ASTTypePrinter.print(sf)); + } + logFile.flush(); + Set>> cardProd = unifyCons.cartesianProduct(); + for (List> xCons : cardProd ){ + Set xConsSet = new HashSet<>(); + for (Constraint constraint : xCons) { + xConsSet.addAll(constraint); + } + //.collect(Collectors.toCollection(ArrayList::new)))) + System.out.println(xConsSet); + Set paraTypeVarNames = 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((a,b) -> { a.addAll(b); return a;} ).get()) + .reduce((a,b) -> { a.addAll(b); return a;} ).get(); + + Set 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(); + + + 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> result = unify.unifySequential(xConsSet, finiteClosure, logFile); + //Set> result = unify.unify(xConsSet, finiteClosure); + System.out.println("RESULT: " + result); + logFile.write("RES: " + result.toString()+"\n"); + logFile.flush(); + results.addAll(result); + } + } + catch (IOException e) { } + + return results.stream().map((unifyPairs -> + new ResultSet(UnifyTypeFactory.convert(unifyPairs, generateTPHMap(cons))))).collect(Collectors.toList()); } - return results.stream().map((unifyPairs -> - new ResultSet(UnifyTypeFactory.convert(unifyPairs, generateTPHMap(cons))))).collect(Collectors.toList()); - } + + /** + * Vererbt alle Variancen + * @param eq The set of constraints + */ + private void varianceInheritance(Set eq) { + Set usedTPH = new HashSet<>(); + Set phSet = eq.stream().map(x -> { + Set 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 phSetVariance = new ArrayList<>(phSet); + phSetVariance.removeIf(x -> (x.getVariance() == 0)); + while(!phSetVariance.isEmpty()) { + PlaceholderType a = phSetVariance.remove(0); + usedTPH.add(a); + //HashMap ht = new HashMap<>(); + //ht.put(a, a.getVariance()); + Set 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))); + } +} private Map generateTPHMap(ConstraintSet constraints) { HashMap ret = new HashMap<>(); @@ -156,4 +257,4 @@ public class JavaTXCompiler { System.out.println(name+".class file generated"); } } -} \ No newline at end of file +} diff --git a/src/de/dhbwstuttgart/parser/SyntaxTreeGenerator/FCGenerator.java b/src/de/dhbwstuttgart/parser/SyntaxTreeGenerator/FCGenerator.java index 24abec67..1714570e 100644 --- a/src/de/dhbwstuttgart/parser/SyntaxTreeGenerator/FCGenerator.java +++ b/src/de/dhbwstuttgart/parser/SyntaxTreeGenerator/FCGenerator.java @@ -57,48 +57,55 @@ public class FCGenerator { params.add(gtvs.get(gtv.getName())); } - Optional hasSuperclass = availableClasses.stream().filter(cl -> forType.getSuperClass().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.getSystemClassLoader().loadClass(forType.getSuperClass().getName().toString())); - }else{ - superClass = hasSuperclass.get(); - } - /* - Die Parameter der superklasse müssen jetzt nach den Angaben in der Subklasse - modifiziert werden - Beispie: Matrix extends Vector> - Den ersten Parameter mit Vector austauschen und dort alle Generics zu den Typplaceholdern in gtvs austauschen - */ - //Hier vermerken, welche Typen im der Superklasse ausgetauscht werden müssen - Iterator itGenParams = superClass.getGenerics().iterator(); - Iterator itSetParams = forType.getSuperClass().getParaList().iterator(); - while(itGenParams.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); - } - RefTypeOrTPHOrWildcardOrGeneric superType = forType.getSuperClass().acceptTV(new TypeExchanger(newGTVs)); - - RefTypeOrTPHOrWildcardOrGeneric t1 = new RefType(forType.getClassName(), params, new NullToken()); - RefTypeOrTPHOrWildcardOrGeneric t2 = superType; - - Pair ret = new Pair(t1, t2, PairOperator.SMALLER); - - List 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); - } + List superClasses = new ArrayList<>(); + superClasses.add(forType.getSuperClass()); + superClasses.addAll(forType.getSuperInterfaces()); List retList = new ArrayList<>(); - retList.add(ret); - retList.addAll(superTypes); + for(RefType superType : superClasses){ + Optional 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.getSystemClassLoader().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 extends Vector> + Den ersten Parameter mit Vector austauschen und dort alle Generics zu den Typplaceholdern in gtvs austauschen + */ + //Hier vermerken, welche Typen im der Superklasse ausgetauscht werden müssen + Iterator itGenParams = superClass.getGenerics().iterator(); + Iterator 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); + } + + RefTypeOrTPHOrWildcardOrGeneric superRefType = superType.acceptTV(new TypeExchanger(newGTVs)); + + RefTypeOrTPHOrWildcardOrGeneric t1 = new RefType(forType.getClassName(), params, new NullToken()); + RefTypeOrTPHOrWildcardOrGeneric t2 = superRefType; + + Pair ret = new Pair(t1, t2, PairOperator.SMALLER); + + List 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); + } + + retList.add(ret); + retList.addAll(superTypes); + } return retList; } diff --git a/src/de/dhbwstuttgart/parser/SyntaxTreeGenerator/StatementGenerator.java b/src/de/dhbwstuttgart/parser/SyntaxTreeGenerator/StatementGenerator.java index aaa31f74..15f2268d 100644 --- a/src/de/dhbwstuttgart/parser/SyntaxTreeGenerator/StatementGenerator.java +++ b/src/de/dhbwstuttgart/parser/SyntaxTreeGenerator/StatementGenerator.java @@ -904,7 +904,7 @@ public class StatementGenerator { funNParams.add(TypePlaceholder.fresh(expression.getStart()))); RefTypeOrTPHOrWildcardOrGeneric lambdaType = TypePlaceholder.fresh(expression.getStart()); //RefType lambdaType = new RefType(reg.getName("Fun"+params.getFormalparalist().size()), - //funNParams, name.getStart()); + //funNParams, name.getStart()); return new LambdaExpression(lambdaType, params, block, expression.getStart()); } } diff --git a/src/de/dhbwstuttgart/parser/SyntaxTreeGenerator/SyntaxTreeGenerator.java b/src/de/dhbwstuttgart/parser/SyntaxTreeGenerator/SyntaxTreeGenerator.java index ed96d2e6..72606713 100644 --- a/src/de/dhbwstuttgart/parser/SyntaxTreeGenerator/SyntaxTreeGenerator.java +++ b/src/de/dhbwstuttgart/parser/SyntaxTreeGenerator/SyntaxTreeGenerator.java @@ -203,20 +203,20 @@ public class SyntaxTreeGenerator{ } Boolean isInterface = false; - List implementedInterfaces = convert(ctx.superinterfaces(), generics); + List implementedInterfaces = convert(ctx.superinterfaces(), generics); return new ClassOrInterface(modifiers, name, fielddecl, methods, konstruktoren, genericClassParameters, superClass, isInterface, implementedInterfaces, offset); } - private List convert(Java8Parser.SuperinterfacesContext ctx, GenericsRegistry generics) { + private List convert(Java8Parser.SuperinterfacesContext ctx, GenericsRegistry generics) { if(ctx == null)return new ArrayList<>(); return convert(ctx.interfaceTypeList(), generics); } - private List convert(Java8Parser.InterfaceTypeListContext ctx, GenericsRegistry generics) { - List ret = new ArrayList<>(); + private List convert(Java8Parser.InterfaceTypeListContext ctx, GenericsRegistry generics) { + List ret = new ArrayList<>(); for(Java8Parser.InterfaceTypeContext interfaceType : ctx.interfaceType()){ - ret.add(TypeGenerator.convert(interfaceType.classType(), reg, generics)); + ret.add((RefType) TypeGenerator.convert(interfaceType.classType(), reg, generics)); } return ret; } @@ -400,7 +400,7 @@ public class SyntaxTreeGenerator{ List fields = convertFields(ctx.interfaceBody()); List methods = convertMethods(ctx.interfaceBody(), name, superClass, generics); - List extendedInterfaces = convert(ctx.extendsInterfaces(), generics); + List extendedInterfaces = convert(ctx.extendsInterfaces(), generics); return new ClassOrInterface(modifiers, name, fields, methods, new ArrayList<>(), genericParams, superClass, true, extendedInterfaces, ctx.getStart()); @@ -423,7 +423,7 @@ public class SyntaxTreeGenerator{ return ret; } - private List convert(Java8Parser.ExtendsInterfacesContext extendsInterfacesContext, GenericsRegistry generics) { + private List convert(Java8Parser.ExtendsInterfacesContext extendsInterfacesContext, GenericsRegistry generics) { if(extendsInterfacesContext == null)return new ArrayList<>(); return convert(extendsInterfacesContext.interfaceTypeList(), generics); } diff --git a/src/de/dhbwstuttgart/parser/SyntaxTreeGenerator/TypeGenerator.java b/src/de/dhbwstuttgart/parser/SyntaxTreeGenerator/TypeGenerator.java index 38399bf0..b4923039 100644 --- a/src/de/dhbwstuttgart/parser/SyntaxTreeGenerator/TypeGenerator.java +++ b/src/de/dhbwstuttgart/parser/SyntaxTreeGenerator/TypeGenerator.java @@ -113,9 +113,7 @@ public class TypeGenerator { if(referenceTypeContext.classOrInterfaceType() != null){ if(referenceTypeContext.classOrInterfaceType().classType_lfno_classOrInterfaceType()!= null){ Java8Parser.ClassType_lfno_classOrInterfaceTypeContext ctx = referenceTypeContext.classOrInterfaceType().classType_lfno_classOrInterfaceType(); - //return convertTypeName(ctx.Identifier().toString(), ctx.typeArguments(),referenceTypeContext.getStart(), reg, generics); - if(ctx.typeArguments() != null)throw new NotImplementedException(); - return convertTypeName(referenceTypeContext.getText(), null,referenceTypeContext.getStart(), reg, generics); + return convertTypeName(ctx.Identifier().toString(), ctx.typeArguments(),referenceTypeContext.getStart(), reg, generics); }else{ throw new NotImplementedException(); } diff --git a/src/de/dhbwstuttgart/syntaxtree/ClassOrInterface.java b/src/de/dhbwstuttgart/syntaxtree/ClassOrInterface.java index 5d5fc3e2..e0c09e92 100644 --- a/src/de/dhbwstuttgart/syntaxtree/ClassOrInterface.java +++ b/src/de/dhbwstuttgart/syntaxtree/ClassOrInterface.java @@ -13,6 +13,7 @@ import de.dhbwstuttgart.typeinference.assumptions.TypeInferenceInformation; import org.antlr.v4.runtime.Token; import java.util.ArrayList; +import java.util.Collection; import java.util.List; /** @@ -26,11 +27,11 @@ public class ClassOrInterface extends SyntaxTreeNode implements TypeScope{ private GenericDeclarationList genericClassParameters; private RefType superClass; protected boolean isInterface; - private List implementedInterfaces; + private List implementedInterfaces; private List constructors; public ClassOrInterface(int modifiers, JavaClassName name, List fielddecl, List methods, List constructors, GenericDeclarationList genericClassParameters, - RefType superClass, Boolean isInterface, List implementedInterfaces, Token offset){ + RefType superClass, Boolean isInterface, List implementedInterfaces, Token offset){ super(offset); this.modifiers = modifiers; this.name = name; @@ -101,4 +102,12 @@ public class ClassOrInterface extends SyntaxTreeNode implements TypeScope{ public void accept(ASTVisitor visitor) { visitor.visit(this); } + + public Collection getSuperInterfaces() { + return implementedInterfaces; + } + + public String toString() { + return this.name.toString() + this.genericClassParameters.toString(); + } } diff --git a/src/de/dhbwstuttgart/syntaxtree/GenericDeclarationList.java b/src/de/dhbwstuttgart/syntaxtree/GenericDeclarationList.java index e316aa6b..6a264684 100644 --- a/src/de/dhbwstuttgart/syntaxtree/GenericDeclarationList.java +++ b/src/de/dhbwstuttgart/syntaxtree/GenericDeclarationList.java @@ -31,4 +31,8 @@ public class GenericDeclarationList extends SyntaxTreeNode implements Iterable PLACEHOLDERS = new ArrayList<>(); public static FiniteClosure generateFC(List fromClasses) throws ClassNotFoundException { /* @@ -113,7 +115,15 @@ public class UnifyTypeFactory { } public static UnifyType convert(TypePlaceholder tph){ - return new PlaceholderType(tph.getName()); + PlaceholderType ntph = new PlaceholderType(tph.getName()); + int in = PLACEHOLDERS.indexOf(ntph); + if (in == -1) { + PLACEHOLDERS.add(ntph); + return ntph; + } + else { + return PLACEHOLDERS.get(in); + } } public static UnifyType convert(GenericRefType t){ diff --git a/src/de/dhbwstuttgart/typeinference/constraints/Pair.java b/src/de/dhbwstuttgart/typeinference/constraints/Pair.java index ab0cb3ea..eb322274 100644 --- a/src/de/dhbwstuttgart/typeinference/constraints/Pair.java +++ b/src/de/dhbwstuttgart/typeinference/constraints/Pair.java @@ -11,6 +11,7 @@ public class Pair implements Serializable public final RefTypeOrTPHOrWildcardOrGeneric TA2; private PairOperator eOperator = PairOperator.SMALLER; + public Pair(RefTypeOrTPHOrWildcardOrGeneric TA1, RefTypeOrTPHOrWildcardOrGeneric TA2 ) { diff --git a/src/de/dhbwstuttgart/typeinference/typeAlgo/TYPEStmt.java b/src/de/dhbwstuttgart/typeinference/typeAlgo/TYPEStmt.java index 108122ac..4dad9de6 100644 --- a/src/de/dhbwstuttgart/typeinference/typeAlgo/TYPEStmt.java +++ b/src/de/dhbwstuttgart/typeinference/typeAlgo/TYPEStmt.java @@ -57,8 +57,8 @@ public class TYPEStmt implements StatementVisitor{ public void visit(LambdaExpression lambdaExpression) { TypePlaceholder tphRetType = TypePlaceholder.fresh(new NullToken()); List lambdaParams = lambdaExpression.params.getFormalparalist().stream().map((formalParameter -> formalParameter.getType())).collect(Collectors.toList()); - //lambdaParams.add(tphRetType); - lambdaParams.add(0,tphRetType); + lambdaParams.add(tphRetType); + //lambdaParams.add(0,tphRetType); constraintsSet.addUndConstraint( new Pair(lambdaExpression.getType(), new FunN(lambdaParams),PairOperator.EQUALSDOT)); @@ -184,7 +184,13 @@ public class TYPEStmt implements StatementVisitor{ receiver.expr.accept(this); } - private final RefType number = new RefType(ASTFactory.createClass(Integer.class).getClassName(), new NullToken()); + private final RefType number = new RefType(ASTFactory.createClass(Number.class).getClassName(), new NullToken()); + private final RefType longg = new RefType(ASTFactory.createClass(Long.class).getClassName(), new NullToken()); + private final RefType integer = new RefType(ASTFactory.createClass(Integer.class).getClassName(), new NullToken()); + private final RefType shortt = new RefType(ASTFactory.createClass(Short.class).getClassName(), new NullToken()); + private final RefType bytee = new RefType(ASTFactory.createClass(Byte.class).getClassName(), new NullToken()); + private final RefType floatt = new RefType(ASTFactory.createClass(Float.class).getClassName(), new NullToken()); + private final RefType doublee = new RefType(ASTFactory.createClass(Double.class).getClassName(), new NullToken()); private final RefType string = new RefType(ASTFactory.createClass(String.class).getClassName(), new NullToken()); private final RefType bool = new RefType(ASTFactory.createClass(Boolean.class).getClassName(), new NullToken()); @Override @@ -205,18 +211,47 @@ public class TYPEStmt implements StatementVisitor{ @Override public void visit(BinaryExpr binary) { - + binary.lexpr.accept(this); + binary.rexpr.accept(this); if(binary.operation.equals(BinaryExpr.Operator.DIV) || binary.operation.equals(BinaryExpr.Operator.MUL)|| binary.operation.equals(BinaryExpr.Operator.MOD)|| binary.operation.equals(BinaryExpr.Operator.ADD)){ Set numericAdditionOrStringConcatenation = new HashSet<>(); - Constraint numeric = new Constraint<>(); + //Zuerst der Fall für Numerische AusdrücPairOpnumericeratorke, das sind Mul, Mod und Div immer: //see: https://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.17 //Expression muss zu Numeric Convertierbar sein. also von Numeric erben - numeric.add(new Pair(binary.lexpr.getType(), number, PairOperator.SMALLERDOT)); - numeric.add(new Pair(binary.rexpr.getType(), number, PairOperator.SMALLERDOT)); + Constraint numeric = new Constraint<>(); + numeric.add(new Pair(binary.lexpr.getType(), bytee, PairOperator.SMALLERDOT)); + numeric.add(new Pair(binary.rexpr.getType(), bytee, PairOperator.SMALLERDOT)); + numeric.add(new Pair(binary.getType(), integer, PairOperator.SMALLERDOT)); + numericAdditionOrStringConcatenation.add(numeric); + numeric = new Constraint<>(); + numeric.add(new Pair(binary.lexpr.getType(), shortt, PairOperator.SMALLERDOT)); + numeric.add(new Pair(binary.rexpr.getType(), shortt, PairOperator.SMALLERDOT)); + numeric.add(new Pair(binary.getType(), integer, PairOperator.SMALLERDOT)); + numericAdditionOrStringConcatenation.add(numeric); + numeric = new Constraint<>(); + numeric.add(new Pair(binary.lexpr.getType(), integer, PairOperator.SMALLERDOT)); + numeric.add(new Pair(binary.rexpr.getType(), integer, PairOperator.SMALLERDOT)); + numeric.add(new Pair(binary.getType(), integer, PairOperator.SMALLERDOT)); + numericAdditionOrStringConcatenation.add(numeric); + numeric = new Constraint<>(); + numeric.add(new Pair(binary.lexpr.getType(), longg, PairOperator.SMALLERDOT)); + numeric.add(new Pair(binary.rexpr.getType(), longg, PairOperator.SMALLERDOT)); + numeric.add(new Pair(binary.getType(), longg, PairOperator.SMALLERDOT)); + numericAdditionOrStringConcatenation.add(numeric); + numeric = new Constraint<>(); + numeric.add(new Pair(binary.lexpr.getType(), floatt, PairOperator.SMALLERDOT)); + numeric.add(new Pair(binary.rexpr.getType(), floatt, PairOperator.SMALLERDOT)); + numeric.add(new Pair(binary.getType(), floatt, PairOperator.SMALLERDOT)); + numericAdditionOrStringConcatenation.add(numeric); + numeric = new Constraint<>(); + numeric.add(new Pair(binary.lexpr.getType(), doublee, PairOperator.SMALLERDOT)); + numeric.add(new Pair(binary.rexpr.getType(), doublee, PairOperator.SMALLERDOT)); + numeric.add(new Pair(binary.getType(), doublee, PairOperator.SMALLERDOT)); + numericAdditionOrStringConcatenation.add(numeric); /* In Java passiert bei den binären Operatoren eine sogenannte Type Promotion: https://docs.oracle.com/javase/specs/jls/se7/html/jls-5.html#jls-5.6.2 @@ -237,10 +272,48 @@ public class TYPEStmt implements StatementVisitor{ binary.operation.equals(BinaryExpr.Operator.BIGGEREQUAL) || binary.operation.equals(BinaryExpr.Operator.BIGGERTHAN) || binary.operation.equals(BinaryExpr.Operator.LESSTHAN)){ - constraintsSet.addUndConstraint(new Pair(binary.lexpr.getType(), number, PairOperator.SMALLERDOT)); - constraintsSet.addUndConstraint(new Pair(binary.rexpr.getType(), number, PairOperator.SMALLERDOT)); + //eingefuegt PL 2018-05-24 + Set numericRelationConcatenation = new HashSet<>(); + Constraint numeric = new Constraint<>(); + numeric.add(new Pair(binary.lexpr.getType(), bytee, PairOperator.SMALLERDOT)); + numeric.add(new Pair(binary.rexpr.getType(), bytee, PairOperator.SMALLERDOT)); + numeric.add(new Pair(binary.getType(), bool, PairOperator.SMALLERDOT)); + numericRelationConcatenation.add(numeric); + numeric = new Constraint<>(); + numeric.add(new Pair(binary.lexpr.getType(), shortt, PairOperator.SMALLERDOT)); + numeric.add(new Pair(binary.rexpr.getType(), shortt, PairOperator.SMALLERDOT)); + numeric.add(new Pair(binary.getType(), bool, PairOperator.SMALLERDOT)); + numericRelationConcatenation.add(numeric); + numeric = new Constraint<>(); + numeric.add(new Pair(binary.lexpr.getType(), integer, PairOperator.SMALLERDOT)); + numeric.add(new Pair(binary.rexpr.getType(), integer, PairOperator.SMALLERDOT)); + numeric.add(new Pair(binary.getType(), bool, PairOperator.SMALLERDOT)); + numericRelationConcatenation.add(numeric); + numeric = new Constraint<>(); + numeric.add(new Pair(binary.lexpr.getType(), longg, PairOperator.SMALLERDOT)); + numeric.add(new Pair(binary.rexpr.getType(), longg, PairOperator.SMALLERDOT)); + numeric.add(new Pair(binary.getType(), bool, PairOperator.SMALLERDOT)); + numericRelationConcatenation.add(numeric); + numeric = new Constraint<>(); + numeric.add(new Pair(binary.lexpr.getType(), floatt, PairOperator.SMALLERDOT)); + numeric.add(new Pair(binary.rexpr.getType(), floatt, PairOperator.SMALLERDOT)); + numeric.add(new Pair(binary.getType(), bool, PairOperator.SMALLERDOT)); + numericRelationConcatenation.add(numeric); + numeric = new Constraint<>(); + numeric.add(new Pair(binary.lexpr.getType(), doublee, PairOperator.SMALLERDOT)); + numeric.add(new Pair(binary.rexpr.getType(), doublee, PairOperator.SMALLERDOT)); + numeric.add(new Pair(binary.getType(), bool, PairOperator.SMALLERDOT)); + numericRelationConcatenation.add(numeric); + + //***ACHTUNG: Moeglicherweise oder und und-Contraint falsch + constraintsSet.addOderConstraint(numericRelationConcatenation); + //***ACHTUNG: Moeglicherweise oder und und-Contraint falsch + + //auskommentiert PL 2018-05-24 + //constraintsSet.addUndConstraint(new Pair(binary.lexpr.getType(), number, PairOperator.SMALLERDOT)); + //constraintsSet.addUndConstraint(new Pair(binary.rexpr.getType(), number, PairOperator.SMALLERDOT)); //Rückgabetyp ist Boolean - constraintsSet.addUndConstraint(new Pair(bool, binary.getType(), PairOperator.EQUALSDOT)); + //constraintsSet.addUndConstraint(new Pair(bool, binary.getType(), PairOperator.EQUALSDOT)); }else{ throw new NotImplementedException(); } diff --git a/src/de/dhbwstuttgart/typeinference/unify/MartelliMontanariUnify.java b/src/de/dhbwstuttgart/typeinference/unify/MartelliMontanariUnify.java index 1c75ea99..087b8943 100644 --- a/src/de/dhbwstuttgart/typeinference/unify/MartelliMontanariUnify.java +++ b/src/de/dhbwstuttgart/typeinference/unify/MartelliMontanariUnify.java @@ -94,7 +94,8 @@ public class MartelliMontanariUnify implements IUnify { // SUBST - Rule if(lhsType instanceof PlaceholderType) { mgu.add((PlaceholderType) lhsType, rhsType); - termsList = termsList.stream().map(mgu::apply).collect(Collectors.toCollection(ArrayList::new)); + //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; } diff --git a/src/de/dhbwstuttgart/typeinference/unify/RuleSet.java b/src/de/dhbwstuttgart/typeinference/unify/RuleSet.java index 8c41660b..5631724b 100644 --- a/src/de/dhbwstuttgart/typeinference/unify/RuleSet.java +++ b/src/de/dhbwstuttgart/typeinference/unify/RuleSet.java @@ -24,13 +24,27 @@ import de.dhbwstuttgart.typeinference.unify.model.Unifier; import de.dhbwstuttgart.typeinference.unify.model.UnifyPair; import de.dhbwstuttgart.typeinference.unify.model.UnifyType; import de.dhbwstuttgart.typeinference.unify.model.WildcardType; +import de.dhbwstuttgart.typeinference.unify.distributeVariance; + +import java.io.FileWriter; +import java.io.IOException; /** * Implementation of the type inference rules. * @author Florian Steurer * */ -public class RuleSet implements IRuleSet{ +public class RuleSet implements IRuleSet{ + + FileWriter logFile; + + RuleSet() { + super(); + } + + RuleSet(FileWriter logFile) { + this.logFile = logFile; + } @Override public Optional reduceUp(UnifyPair pair) { @@ -47,7 +61,7 @@ public class RuleSet implements IRuleSet{ return Optional.empty(); // Rule is applicable, unpack the SuperType - return Optional.of(new UnifyPair(lhsType, ((SuperType) rhsType).getSuperedType(), PairOperator.SMALLERDOT)); + return Optional.of(new UnifyPair(lhsType, ((SuperType) rhsType).getSuperedType(), PairOperator.SMALLERDOT, pair.getSubstitution(), pair.getBasePair())); } @Override @@ -65,7 +79,7 @@ public class RuleSet implements IRuleSet{ return Optional.empty(); // Rule is applicable, unpack the ExtendsType - return Optional.of(new UnifyPair(((ExtendsType) lhsType).getExtendedType(), rhsType, PairOperator.SMALLERDOT)); + return Optional.of(new UnifyPair(((ExtendsType) lhsType).getExtendedType(), rhsType, PairOperator.SMALLERDOT, pair.getSubstitution(), pair.getBasePair())); } @Override @@ -83,7 +97,7 @@ public class RuleSet implements IRuleSet{ return Optional.empty(); // Rule is applicable, unpack both sides - return Optional.of(new UnifyPair(((ExtendsType) lhsType).getExtendedType(),((SuperType) rhsType).getSuperedType(), PairOperator.SMALLERDOT)); + return Optional.of(new UnifyPair(((ExtendsType) lhsType).getExtendedType(),((SuperType) rhsType).getSuperedType(), PairOperator.SMALLERDOT, pair.getSubstitution(), pair.getBasePair())); } @Override @@ -133,7 +147,7 @@ public class RuleSet implements IRuleSet{ Set result = new HashSet<>(); for(int rhsIdx = 0; rhsIdx < extYParams.size(); rhsIdx++) - result.add(new UnifyPair(xParams.get(pi[rhsIdx]), extYParams.get(rhsIdx), PairOperator.SMALLERDOTWC)); + result.add(new UnifyPair(xParams.get(pi[rhsIdx]), extYParams.get(rhsIdx), PairOperator.SMALLERDOTWC, pair.getSubstitution(), pair.getBasePair())); return Optional.of(result); } @@ -184,7 +198,7 @@ public class RuleSet implements IRuleSet{ return Optional.empty(); for(int rhsIdx = 0; rhsIdx < supYParams.size(); rhsIdx++) - result.add(new UnifyPair(supYParams.get(rhsIdx), xParams.get(pi[rhsIdx]), PairOperator.SMALLERDOTWC)); + result.add(new UnifyPair(supYParams.get(rhsIdx), xParams.get(pi[rhsIdx]), PairOperator.SMALLERDOTWC, pair.getSubstitution(), pair.getBasePair())); return Optional.of(result); } @@ -215,7 +229,7 @@ public class RuleSet implements IRuleSet{ TypeParams rhsTypeParams = rhsType.getTypeParams(); for(int i = 0; i < lhsTypeParams.size(); i++) - result.add(new UnifyPair(lhsTypeParams.get(i), rhsTypeParams.get(i), PairOperator.EQUALSDOT)); + result.add(new UnifyPair(lhsTypeParams.get(i), rhsTypeParams.get(i), PairOperator.EQUALSDOT, pair.getSubstitution(), pair.getBasePair())); return Optional.of(result); } @@ -236,19 +250,53 @@ public class RuleSet implements IRuleSet{ ReferenceType lhsSType = (ReferenceType) c; ReferenceType rhsSType = (ReferenceType) d; + //try { + // logFile.write("PAIR Rules: " + pair + "\n"); + // logFile.flush(); + //} + //catch (IOException e) { } + if(lhsSType.getTypeParams().empty() || lhsSType.getTypeParams().size() != rhsSType.getTypeParams().size()) return Optional.empty(); UnifyType cFromFc = fc.getLeftHandedType(c.getName()).orElse(null); + //2018-02-23: liefert Vector>: Das kann nicht sein. + + //NOCHMAL UEBERPRUEFEN + //PL 18-02-09 Eingfuegt Anfang + //C und D koennen auch gleich sein. + if (c.getName().equals(d.getName())) { + Set result = new HashSet<>(); + TypeParams rhsTypeParams = d.getTypeParams(); + TypeParams lhsTypeParams = c.getTypeParams(); + for(int rhsIdx = 0; rhsIdx < c.getTypeParams().size(); rhsIdx++) + result.add(new UnifyPair(lhsTypeParams.get(rhsIdx), rhsTypeParams.get(rhsIdx), PairOperator.SMALLERDOTWC, pair.getSubstitution(), pair.getBasePair())); + + return Optional.of(result); + } + //PL 18-02-09 Eingfuegt ENDE + + //try { + // logFile.write("cFromFc: " + cFromFc); + // logFile.flush(); + //} + //catch (IOException e) { } if(cFromFc == null || !cFromFc.getTypeParams().arePlaceholders()) return Optional.empty(); UnifyType dFromFc = fc.getAncestors(cFromFc).stream().filter(x -> x.getName().equals(d.getName())).findAny().orElse(null); + //try { + // logFile.write("cFromFc: " + cFromFc); + // logFile.flush(); + //} + //catch (IOException e) { } + if(dFromFc == null || !dFromFc.getTypeParams().arePlaceholders() || dFromFc.getTypeParams().size() != cFromFc.getTypeParams().size()) return Optional.empty(); - + //System.out.println("cFromFc: " + cFromFc); + //System.out.println("dFromFc: " + dFromFc); int[] pi = pi(cFromFc.getTypeParams(), dFromFc.getTypeParams()); if(pi.length == 0) @@ -259,7 +307,7 @@ public class RuleSet implements IRuleSet{ Set result = new HashSet<>(); for(int rhsIdx = 0; rhsIdx < rhsTypeParams.size(); rhsIdx++) - result.add(new UnifyPair(lhsTypeParams.get(pi[rhsIdx]), rhsTypeParams.get(rhsIdx), PairOperator.SMALLERDOTWC)); + result.add(new UnifyPair(lhsTypeParams.get(pi[rhsIdx]), rhsTypeParams.get(rhsIdx), PairOperator.SMALLERDOTWC, pair.getSubstitution(), pair.getBasePair())); return Optional.of(result); } @@ -314,7 +362,7 @@ public class RuleSet implements IRuleSet{ TypeParams rhsTypeParams = rhsSType.getTypeParams(); TypeParams lhsTypeParams = lhsSType.getTypeParams(); for(int i = 0; i < rhsTypeParams.size(); i++) - result.add(new UnifyPair(lhsTypeParams.get(i), rhsTypeParams.get(i), PairOperator.EQUALSDOT)); + result.add(new UnifyPair(lhsTypeParams.get(i), rhsTypeParams.get(i), PairOperator.EQUALSDOT, pair.getSubstitution(), pair.getBasePair())); return Optional.of(result); } @@ -365,7 +413,7 @@ public class RuleSet implements IRuleSet{ if(!(pair.getRhsType() instanceof PlaceholderType)) return Optional.empty(); - return Optional.of(new UnifyPair(pair.getRhsType(), pair.getLhsType(), PairOperator.EQUALSDOT)); + return Optional.of(new UnifyPair(pair.getRhsType(), pair.getLhsType(), PairOperator.EQUALSDOT, pair.getSubstitution(), pair.getBasePair())); } @Override @@ -407,11 +455,19 @@ public class RuleSet implements IRuleSet{ TypeParams typeDParams = typeD.getTypeParams(); TypeParams typeDgenParams = typeDgen.getTypeParams(); + //System.out.println("Pair: " +pair); + //System.out.println("typeD: " +typeD); + //System.out.println("typeDParams: " +typeDParams); + //System.out.println("typeDgen: " +typeD); + //System.out.println("typeDgenParams: " +typeDgenParams); Unifier unif = Unifier.identity(); - for(int i = 0; i < typeDParams.size(); i++) + for(int i = 0; i < typeDParams.size(); i++) { + //System.out.println("ADAPT" +typeDgenParams); + if (typeDgenParams.get(i) instanceof PlaceholderType) unif.add((PlaceholderType) typeDgenParams.get(i), typeDParams.get(i)); - - return Optional.of(new UnifyPair(unif.apply(newLhs), typeDs, PairOperator.SMALLERDOT)); + else System.out.println("ERROR"); + } + return Optional.of(new UnifyPair(unif.apply(newLhs), typeDs, PairOperator.SMALLERDOT, pair.getSubstitution(), pair.getBasePair())); } @Override @@ -457,7 +513,7 @@ public class RuleSet implements IRuleSet{ for(int i = 1; i < typeDParams.size(); i++) unif.add((PlaceholderType) typeDgenParams.get(i), typeDParams.get(i)); - return Optional.of(new UnifyPair(unif.apply(newLhs), typeExtDs, PairOperator.SMALLERDOTWC)); + return Optional.of(new UnifyPair(unif.apply(newLhs), typeExtDs, PairOperator.SMALLERDOTWC, pair.getSubstitution(), pair.getBasePair())); } @Override @@ -509,7 +565,7 @@ public class RuleSet implements IRuleSet{ for(int i = 1; i < typeDParams.size(); i++) unif.add((PlaceholderType) typeSupDsgenParams.get(i), typeDParams.get(i)); - return Optional.of(new UnifyPair(unif.apply(newLhs), newRhs, PairOperator.SMALLERDOTWC)); + return Optional.of(new UnifyPair(unif.apply(newLhs), newRhs, PairOperator.SMALLERDOTWC, pair.getSubstitution(), pair.getBasePair())); } /** @@ -581,8 +637,8 @@ public class RuleSet implements IRuleSet{ && typeMap.get(lhsType) > 1 // The type occurs in more pairs in the set than just the recent pair. && !rhsType.getTypeParams().occurs(lhsType)) { Unifier uni = new Unifier(lhsType, rhsType); - result = result.stream().map(uni::apply).collect(Collectors.toCollection(ArrayList::new)); - result1 = result1.stream().map(uni::apply).collect(Collectors.toCollection(LinkedList::new)); + result = result.stream().map(x -> uni.apply(pair,x)).collect(Collectors.toCollection(ArrayList::new)); + result1 = result1.stream().map(x -> uni.apply(pair,x)).collect(Collectors.toCollection(LinkedList::new)); applied = true; } @@ -602,7 +658,7 @@ public class RuleSet implements IRuleSet{ if(!(lhsType instanceof ExtendsType) || !(rhsType instanceof ExtendsType)) return Optional.empty(); - return Optional.of(new UnifyPair(((ExtendsType) lhsType).getExtendedType(), ((ExtendsType) rhsType).getExtendedType(), PairOperator.SMALLERDOT)); + return Optional.of(new UnifyPair(((ExtendsType) lhsType).getExtendedType(), ((ExtendsType) rhsType).getExtendedType(), PairOperator.SMALLERDOT, pair.getSubstitution(), pair.getBasePair())); } @Override @@ -615,7 +671,7 @@ public class RuleSet implements IRuleSet{ if(!(lhsType instanceof ReferenceType) || !(rhsType instanceof ExtendsType)) return Optional.empty(); - return Optional.of(new UnifyPair(lhsType, ((ExtendsType) rhsType).getExtendedType(), PairOperator.SMALLERDOT)); + return Optional.of(new UnifyPair(lhsType, ((ExtendsType) rhsType).getExtendedType(), PairOperator.SMALLERDOT, pair.getSubstitution(), pair.getBasePair())); } @Override @@ -628,7 +684,7 @@ public class RuleSet implements IRuleSet{ if(!(lhsType instanceof SuperType) || !(rhsType instanceof SuperType)) return Optional.empty(); - return Optional.of(new UnifyPair(((SuperType) rhsType).getSuperedType(), ((SuperType) lhsType).getSuperedType(), PairOperator.SMALLERDOT)); + return Optional.of(new UnifyPair(((SuperType) rhsType).getSuperedType(), ((SuperType) lhsType).getSuperedType(), PairOperator.SMALLERDOT, pair.getSubstitution(), pair.getBasePair())); } @Override @@ -641,9 +697,11 @@ public class RuleSet implements IRuleSet{ if(!(lhsType instanceof ReferenceType) || !(rhsType instanceof SuperType)) return Optional.empty(); - return Optional.of(new UnifyPair(((SuperType) rhsType).getSuperedType(), lhsType, PairOperator.SMALLERDOTWC)); + return Optional.of(new UnifyPair(((SuperType) rhsType).getSuperedType(), lhsType, PairOperator.SMALLERDOTWC, pair.getSubstitution(), pair.getBasePair())); } + /* PL 2018-03-06 auskommentiert sind mutmaßlich falsch + * vgl. JAVA_BSP/Wildcard6.java @Override public Optional reduceWildcardLowUp(UnifyPair pair) { if(pair.getPairOp() != PairOperator.SMALLERDOTWC) @@ -670,6 +728,7 @@ public class RuleSet implements IRuleSet{ return Optional.of(new UnifyPair(((SuperType) lhsType).getSuperedType(), ((ExtendsType) rhsType).getExtendedType(), PairOperator.EQUALSDOT)); } + @Override public Optional reduceWildcardLeft(UnifyPair pair) { if(pair.getPairOp() != PairOperator.SMALLERDOTWC) @@ -686,7 +745,7 @@ public class RuleSet implements IRuleSet{ return Optional.empty(); } - + */ @Override public Optional> reduceFunN(UnifyPair pair) { if((pair.getPairOp() != PairOperator.SMALLERDOT) @@ -709,13 +768,19 @@ public class RuleSet implements IRuleSet{ Set result = new HashSet(); - result.add(new UnifyPair(funNLhsType.getTypeParams().get(0), funNRhsType.getTypeParams().get(0), PairOperator.SMALLERDOT)); - for(int i = 1; i < funNLhsType.getTypeParams().size(); i++) - result.add(new UnifyPair(funNRhsType.getTypeParams().get(i), funNLhsType.getTypeParams().get(i), 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())); + 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.stream().forEach(x -> { UnifyType l = x.getLhsType(); + if (l instanceof PlaceholderType) { ((PlaceholderType)l).disableWildcardtable(); } + UnifyType r = x.getRhsType(); + if (r instanceof PlaceholderType) { ((PlaceholderType)r).disableWildcardtable(); } + } ); return Optional.of(result); } - + + @Override public Optional> greaterFunN(UnifyPair pair) { if(pair.getPairOp() != PairOperator.SMALLERDOT) @@ -731,15 +796,29 @@ public class RuleSet implements IRuleSet{ Set result = new HashSet(); + Integer variance = ((PlaceholderType)rhsType).getVariance(); + Integer inversVariance = distributeVariance.inverseVariance(variance); + UnifyType[] freshPlaceholders = new UnifyType[funNLhsType.getTypeParams().size()]; - for(int i = 0; i < freshPlaceholders.length; i++) + for(int i = 0; i < freshPlaceholders.length-1; i++) { freshPlaceholders[i] = PlaceholderType.freshPlaceholder(); + ((PlaceholderType)freshPlaceholders[i]).setVariance(inversVariance); + } + freshPlaceholders[freshPlaceholders.length-1] = PlaceholderType.freshPlaceholder(); + ((PlaceholderType)freshPlaceholders[freshPlaceholders.length-1]).setVariance(variance); + result.add(new UnifyPair(funNLhsType.getTypeParams().get(funNLhsType.getTypeParams().size()-1), freshPlaceholders[funNLhsType.getTypeParams().size()-1], PairOperator.SMALLERDOT, pair.getSubstitution(), pair.getBasePair())); - result.add(new UnifyPair(funNLhsType.getTypeParams().get(0), freshPlaceholders[0], PairOperator.SMALLERDOT)); - for(int i = 1; i < funNLhsType.getTypeParams().size(); i++) - result.add(new UnifyPair(freshPlaceholders[i], funNLhsType.getTypeParams().get(i), PairOperator.SMALLERDOT)); - result.add(new UnifyPair(rhsType, funNLhsType.setTypeParams(new TypeParams(freshPlaceholders)), PairOperator.EQUALSDOT)); + for(int i = 0; i < funNLhsType.getTypeParams().size()-1; i++) { + result.add(new UnifyPair(freshPlaceholders[i], funNLhsType.getTypeParams().get(i), PairOperator.SMALLERDOT, pair.getSubstitution(), pair.getBasePair())); + } + result.add(new UnifyPair(rhsType, funNLhsType.setTypeParams(new TypeParams(freshPlaceholders)), PairOperator.EQUALSDOT, pair.getSubstitution(), pair.getBasePair())); + + result.stream().forEach(x -> { UnifyType l = x.getLhsType(); + if (l instanceof PlaceholderType) { ((PlaceholderType)l).disableWildcardtable(); } + UnifyType r = x.getRhsType(); + if (r instanceof PlaceholderType) { ((PlaceholderType)r).disableWildcardtable(); } + } ); return Optional.of(result); } @@ -758,15 +837,30 @@ public class RuleSet implements IRuleSet{ Set result = new HashSet(); + Integer variance = ((PlaceholderType)lhsType).getVariance(); + Integer inversVariance = distributeVariance.inverseVariance(variance); + UnifyType[] freshPlaceholders = new UnifyType[funNRhsType.getTypeParams().size()]; - for(int i = 0; i < freshPlaceholders.length; i++) + for(int i = 0; i < freshPlaceholders.length-1; i++) { freshPlaceholders[i] = PlaceholderType.freshPlaceholder(); + ((PlaceholderType)freshPlaceholders[i]).setVariance(inversVariance); + } + freshPlaceholders[freshPlaceholders.length-1] = PlaceholderType.freshPlaceholder(); + ((PlaceholderType)freshPlaceholders[freshPlaceholders.length-1]).setVariance(variance); - result.add(new UnifyPair(freshPlaceholders[0], funNRhsType.getTypeParams().get(0), PairOperator.SMALLERDOT)); - for(int i = 1; i < funNRhsType.getTypeParams().size(); i++) - result.add(new UnifyPair(funNRhsType.getTypeParams().get(i), freshPlaceholders[i], PairOperator.SMALLERDOT)); - result.add(new UnifyPair(lhsType, funNRhsType.setTypeParams(new TypeParams(freshPlaceholders)), PairOperator.EQUALSDOT)); + result.add(new UnifyPair(freshPlaceholders[funNRhsType.getTypeParams().size()-1], funNRhsType.getTypeParams().get(funNRhsType.getTypeParams().size()-1), PairOperator.SMALLERDOT, pair.getSubstitution(), pair.getBasePair())); + for(int i = 0; i < funNRhsType.getTypeParams().size()-1; i++) { + result.add(new UnifyPair(funNRhsType.getTypeParams().get(i), freshPlaceholders[i], PairOperator.SMALLERDOT, pair.getSubstitution(), pair.getBasePair())); + } + + result.add(new UnifyPair(lhsType, funNRhsType.setTypeParams(new TypeParams(freshPlaceholders)), PairOperator.EQUALSDOT, pair.getSubstitution(), pair.getBasePair())); + + result.stream().forEach(x -> { UnifyType l = x.getLhsType(); + if (l instanceof PlaceholderType) { ((PlaceholderType)l).disableWildcardtable(); } + UnifyType r = x.getRhsType(); + if (r instanceof PlaceholderType) { ((PlaceholderType)r).disableWildcardtable(); } + } ); return Optional.of(result); } @@ -780,7 +874,7 @@ public class RuleSet implements IRuleSet{ if(!(lhsType instanceof PlaceholderType) || !(rhsType instanceof ReferenceType)) return Optional.empty(); - return Optional.of(new UnifyPair(lhsType, rhsType, PairOperator.EQUALSDOT)); + return Optional.of(new UnifyPair(lhsType, rhsType, PairOperator.EQUALSDOT, pair.getSubstitution(), pair.getBasePair())); } @Override @@ -799,11 +893,11 @@ public class RuleSet implements IRuleSet{ Set result = new HashSet<>(); if(isGen) - result.add(new UnifyPair(rhsType, lhsType, PairOperator.EQUALSDOT)); + result.add(new UnifyPair(rhsType, lhsType, PairOperator.EQUALSDOT, pair.getSubstitution(), pair.getBasePair())); else { UnifyType freshTph = PlaceholderType.freshPlaceholder(); - result.add(new UnifyPair(rhsType, new ExtendsType(freshTph), PairOperator.EQUALSDOT)); - result.add(new UnifyPair(extendedType, freshTph, PairOperator.SMALLERDOT)); + result.add(new UnifyPair(rhsType, new ExtendsType(freshTph), PairOperator.EQUALSDOT, pair.getSubstitution(), pair.getBasePair())); + result.add(new UnifyPair(extendedType, freshTph, PairOperator.SMALLERDOT, pair.getSubstitution(), pair.getBasePair())); } return Optional.of(result); @@ -825,11 +919,11 @@ public class RuleSet implements IRuleSet{ Set result = new HashSet<>(); if(isGen) - result.add(new UnifyPair(rhsType, lhsType, PairOperator.EQUALSDOT)); + result.add(new UnifyPair(rhsType, lhsType, PairOperator.EQUALSDOT, pair.getSubstitution(), pair.getBasePair())); else { UnifyType freshTph = PlaceholderType.freshPlaceholder(); - result.add(new UnifyPair(rhsType, new SuperType(freshTph), PairOperator.EQUALSDOT)); - result.add(new UnifyPair(freshTph, superedType, PairOperator.SMALLERDOT)); + result.add(new UnifyPair(rhsType, new SuperType(freshTph), PairOperator.EQUALSDOT, pair.getSubstitution(), pair.getBasePair())); + result.add(new UnifyPair(freshTph, superedType, PairOperator.SMALLERDOT, pair.getSubstitution(), pair.getBasePair())); } return Optional.of(result); diff --git a/src/de/dhbwstuttgart/typeinference/unify/TypeUnify.java b/src/de/dhbwstuttgart/typeinference/unify/TypeUnify.java index f457fbb8..69ed93b2 100644 --- a/src/de/dhbwstuttgart/typeinference/unify/TypeUnify.java +++ b/src/de/dhbwstuttgart/typeinference/unify/TypeUnify.java @@ -1,5 +1,6 @@ package de.dhbwstuttgart.typeinference.unify; +import java.io.FileWriter; import java.util.Set; import java.util.concurrent.ForkJoinPool; @@ -7,16 +8,16 @@ import de.dhbwstuttgart.typeinference.unify.interfaces.IFiniteClosure; import de.dhbwstuttgart.typeinference.unify.model.UnifyPair; public class TypeUnify { - public Set> unify(Set eq, IFiniteClosure fc) { - TypeUnifyTask unifyTask = new TypeUnifyTask(eq, fc, true); + public Set> unify(Set eq, IFiniteClosure fc, FileWriter logFile) { + TypeUnifyTask unifyTask = new TypeUnifyTask(eq, fc, true, logFile); ForkJoinPool pool = new ForkJoinPool(); pool.invoke(unifyTask); Set> res = unifyTask.join(); return res; } - public Set> unifySequential(Set eq, IFiniteClosure fc) { - TypeUnifyTask unifyTask = new TypeUnifyTask(eq, fc, false); + public Set> unifySequential(Set eq, IFiniteClosure fc, FileWriter logFile) { + TypeUnifyTask unifyTask = new TypeUnifyTask(eq, fc, false, logFile); Set> res = unifyTask.compute(); return res; } diff --git a/src/de/dhbwstuttgart/typeinference/unify/TypeUnifyTask.java b/src/de/dhbwstuttgart/typeinference/unify/TypeUnifyTask.java index e51679e2..1d5ca564 100644 --- a/src/de/dhbwstuttgart/typeinference/unify/TypeUnifyTask.java +++ b/src/de/dhbwstuttgart/typeinference/unify/TypeUnifyTask.java @@ -3,7 +3,9 @@ package de.dhbwstuttgart.typeinference.unify; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.HashMap; import java.util.HashSet; +import java.util.Iterator; import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.List; @@ -11,7 +13,9 @@ import java.util.Map.Entry; import java.util.Optional; import java.util.Set; import java.util.concurrent.RecursiveTask; +import java.util.function.BinaryOperator; import java.util.stream.Collectors; +import java.util.stream.Stream; import de.dhbwstuttgart.typeinference.unify.interfaces.IFiniteClosure; import de.dhbwstuttgart.typeinference.unify.interfaces.IRuleSet; @@ -25,16 +29,27 @@ 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; +import de.dhbwstuttgart.typeinference.unify.model.OrderingUnifyPair; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; + +import com.google.common.collect.Ordering; /** * Implementation of the type unification algorithm * @author Florian Steurer */ -public class TypeUnifyTask extends RecursiveTask>> { +public class TypeUnifyTask extends RecursiveTask>> { private static final long serialVersionUID = 1L; private static int i = 0; + private boolean printtag = false; + + public static final String rootDirectory = System.getProperty("user.dir")+"/test/logFiles/"; + FileWriter logFile; /** * The implementation of setOps that will be used during the unification @@ -49,23 +64,75 @@ public class TypeUnifyTask extends RecursiveTask>> { /** * The implementation of the rules that will be used during the unification. */ - protected IRuleSet rules = new RuleSet(); + protected IRuleSet rules; protected Set eq; protected IFiniteClosure fc; + protected Ordering> oup; + protected boolean parallel; - public TypeUnifyTask(Set eq, IFiniteClosure fc, boolean parallel) { + Integer nOfUnify = 0; + + Integer noUndefPair = 0; + + Integer noAllErasedElements = 0; + + Integer noBacktracking = 0; + + public TypeUnifyTask() { + rules = new RuleSet(); + } + + public TypeUnifyTask(Set eq, IFiniteClosure fc, boolean parallel, FileWriter logFile) { this.eq = eq; this.fc = fc; + this.oup = new OrderingUnifyPair(fc); this.parallel = parallel; + this.logFile = logFile; + rules = new RuleSet(logFile); } - + + + /** + * Vererbt alle Variancen + * @param eq The set of constraints + */ + /* PL 2018-05- 17 verschoben nach JavaTXCompiler + private void varianceInheritance(Set eq) { + Set usedTPH = new HashSet<>(); + Set phSet = eq.stream().map(x -> { + Set 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 phSetVariance = new ArrayList<>(phSet); + phSetVariance.removeIf(x -> (x.getVariance() == 0)); + while(!phSetVariance.isEmpty()) { + PlaceholderType a = phSetVariance.remove(0); + usedTPH.add(a); + //HashMap ht = new HashMap<>(); + //ht.put(a, a.getVariance()); + Set 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))); + } +} +*/ @Override protected Set> compute() { - return unify(eq, fc, parallel); + Set> res = unify(eq, fc, parallel); + if (isUndefinedPairSetSet(res)) { return new HashSet<>(); } + else return res; } /** @@ -74,11 +141,38 @@ public class TypeUnifyTask extends RecursiveTask>> { * @param fc The finite closure * @return The set of all principal type unifiers */ - protected Set> unify(Set eq, IFiniteClosure fc, boolean parallel) { + protected Set> unify(Set eq, IFiniteClosure fc, boolean parallel) { + Set aas = eq.stream().filter(x -> x.getLhsType().getName().equals("AA") //&& x.getPairOp().equals(PairOperator.SMALLERDOT) + ).collect(Collectors.toCollection(HashSet::new)); + writeLog(nOfUnify.toString() + " AA: " + aas.toString()); + if (aas.isEmpty()) { + System.out.println(""); + } /* * Step 1: Repeated application of reduce, adapt, erase, swap */ - //System.out.println("Unifikation: " + eq); + nOfUnify++; + writeLog(nOfUnify.toString() + " Unifikation: " + eq.toString()); + //eq = eq.stream().map(x -> {x.setVariance((byte)-1); return x;}).collect(Collectors.toCollection(HashSet::new)); + + /* + * Variancen auf alle Gleichungen vererben + */ + //PL 2018-05-17 nach JavaTXCompiler verschoben + //varianceInheritance(eq); + + /* + * ? extends ? extends Theta rausfiltern + */ + Set doubleExt = eq.stream().filter(x -> (x.wrongWildcard())).map(x -> { x.setUndefinedPair(); return x;}) + .collect(Collectors.toCollection(HashSet::new)); + if (doubleExt.size() > 0) { + Set> ret = new HashSet<>(); + ret.add(doubleExt); + return ret; + } + + Set eq0 = applyTypeUnificationRules(eq, fc); /* @@ -99,7 +193,7 @@ public class TypeUnifyTask extends RecursiveTask>> { // cartesian product of the sets created by pattern matching. List>> topLevelSets = new ArrayList<>(); - System.out.println(eq2s); + //System.out.println(eq2s); if(eq1s.size() != 0) { // Do not add empty sets or the cartesian product will always be empty. Set> wrap = new HashSet<>(); @@ -122,22 +216,34 @@ public class TypeUnifyTask extends RecursiveTask>> { // Sets that originate from pair pattern matching // Sets of the "second level" Set undefinedPairs = new HashSet<>(); + if (printtag) System.out.println("eq2s " + eq2s); + //writeLog("BufferSet: " + bufferSet.toString()+"\n"); Set>>> secondLevelSets = calculatePairSets(eq2s, fc, undefinedPairs); //PL 2017-09-20: Im calculatePairSets wird möglicherweise O .< java.lang.Integer //nicht ausgewertet Faculty Beispiel im 1. Schritt //PL 2017-10-03 geloest, muesste noch mit FCs mit kleineren //Typen getestet werden. + if (printtag) System.out.println("secondLevelSets:" +secondLevelSets); // If pairs occured that did not match one of the cartesian product cases, // those pairs are contradictory and the unification is impossible. - if(!undefinedPairs.isEmpty()) - return new HashSet<>(); + if(!undefinedPairs.isEmpty()) { + noUndefPair++; + for (UnifyPair up : undefinedPairs) { + writeLog(noUndefPair.toString() + " UndefinedPairs; " + up); + writeLog("BasePair; " + up.getBasePair()); + } + Set> error = new HashSet<>(); + undefinedPairs = undefinedPairs.stream().map(x -> { x.setUndefinedPair(); return x;}).collect(Collectors.toCollection(HashSet::new)); + error.add(undefinedPairs); + return error; + } /* Up to here, no cartesian products are calculated. * filters for pairs and sets can be applied here */ - // Sub cartesian products of the second level (pattern matched) sets + // Alternative: Sub cartesian products of the second level (pattern matched) sets // "the big (x)" - for(Set>> secondLevelSet : secondLevelSets) { + /* for(Set>> secondLevelSet : secondLevelSets) { //System.out.println("secondLevelSet "+secondLevelSet.size()); List>> secondLevelSetList = new ArrayList<>(secondLevelSet); Set>> cartResult = setOps.cartesianProduct(secondLevelSetList); @@ -153,62 +259,108 @@ public class TypeUnifyTask extends RecursiveTask>> { flat1.addAll(s1); flat.add(flat1); } - topLevelSets.add(flat); + //topLevelSets.add(flat); } + */ + //Alternative KEIN KARTESISCHES PRODUKT der secondlevel Ebene bilden + for(Set>> secondLevelSet : secondLevelSets) { + for (Set> secondlevelelem : secondLevelSet) { + topLevelSets.add(secondlevelelem); + } + } + //System.out.println(topLevelSets); + //System.out.println(); + + + //Aufruf von computeCartesianRecursive ANFANG + return computeCartesianRecursive(new HashSet<>(), new ArrayList<>(topLevelSets), eq, fc, parallel); + + } + + + Set> unify2(Set> setToFlatten, Set eq, IFiniteClosure fc, boolean parallel) { + //Aufruf von computeCartesianRecursive ENDE + + //keine Ahnung woher das kommt + //Set> setToFlatten = topLevelSets.stream().map(x -> x.iterator().next()).collect(Collectors.toCollection(HashSet::new)); + + //Muss auskommentiert werden, wenn computeCartesianRecursive ANFANG // Cartesian product over all (up to 10) top level sets - Set>> eqPrimeSet = setOps.cartesianProduct(topLevelSets) - .stream().map(x -> new HashSet<>(x)) - .collect(Collectors.toCollection(HashSet::new)); + //Set>> eqPrimeSet = setOps.cartesianProduct(topLevelSets) + // .stream().map(x -> new HashSet<>(x)) + // .collect(Collectors.toCollection(HashSet::new)); + //Muss auskommentiert werden, wenn computeCartesianRecursive ENDE Set> eqPrimePrimeSet = new HashSet<>(); Set forks = new HashSet<>(); - for(Set> setToFlatten : eqPrimeSet) { + + //Muss auskommentiert werden, wenn computeCartesianRecursive ANFANG + //for(Set> setToFlatten : eqPrimeSet) { // Flatten the cartesian product + //Muss auskommentiert werden, wenn computeCartesianRecursive ENDE Set eqPrime = new HashSet<>(); setToFlatten.stream().forEach(x -> eqPrime.addAll(x)); /* * Step 5: Substitution */ - System.out.println("vor Subst: " + eqPrime); + //System.out.println("vor Subst: " + eqPrime); Optional> eqPrimePrime = rules.subst(eqPrime); /* * Step 6 a) Restart (fork) for pairs where subst was applied */ if(parallel) { - if //(eqPrime.equals(eq)) //PL 2017-09-29 auskommentiert und durch - (!eqPrimePrime.isPresent()) //PL 2071-09-29 dies ersetzt - //Begruendung: Wenn in der Substitution keine Veraenderung - //(!eqPrimePrime.isPresent()) erfolgt ist, ist das Ergebnis erzielt. + if (eqPrime.equals(eq) && !eqPrimePrime.isPresent()) //PL 2017-09-29 //(!eqPrimePrime.isPresent()) auskommentiert und durch + //PL 2017-09-29 dies ersetzt //(!eqPrimePrime.isPresent()) + //PL 2018-05-18 beide Bedingungen muessen gelten, da eqPrime Veränderungen in allem ausser subst + //eqPrimePrime Veraenderungen in subst repraesentieren. eqPrimePrimeSet.add(eqPrime); else if(eqPrimePrime.isPresent()) { - System.out.println("nextStep: " + eqPrimePrime.get()); - TypeUnifyTask fork = new TypeUnifyTask(eqPrimePrime.get(), fc, true); + //System.out.println("nextStep: " + eqPrimePrime.get()); + TypeUnifyTask fork = new TypeUnifyTask(eqPrimePrime.get(), fc, true, logFile); forks.add(fork); fork.fork(); } else { - System.out.println("nextStep: " + eqPrime); - TypeUnifyTask fork = new TypeUnifyTask(eqPrime, fc, true); + //System.out.println("nextStep: " + eqPrime); + TypeUnifyTask fork = new TypeUnifyTask(eqPrime, fc, true, logFile); forks.add(fork); fork.fork(); } } else { // sequentiell (Step 6b is included) - if //(eqPrime.equals(eq)) //PL 2017-09-29 auskommentiert und durch - (!eqPrimePrime.isPresent()) //PL 2071-09-29 dies ersetzt - //Begruendung: Wenn in der Substitution keine Veraenderung - //(!eqPrimePrime.isPresent()) erfolgt ist, ist das Ergebnis erzielt. + if (printtag) System.out.println("nextStep: " + eqPrimePrime); + if (eqPrime.equals(eq) && !eqPrimePrime.isPresent()) { //PL 2017-09-29 //(!eqPrimePrime.isPresent()) auskommentiert und durch + //PL 2017-09-29 dies ersetzt //(!eqPrimePrime.isPresent()) + //PL 2018-05-18 beide Bedingungen muessen gelten, da eqPrime Veränderungen in allem ausser subst + //eqPrimePrime Veraenderungen in subst repraesentieren. + try { + if (isSolvedForm(eqPrime)) { + logFile.write(eqPrime.toString()+"\n"); + logFile.flush(); + } + } + catch (IOException e) { } eqPrimePrimeSet.add(eqPrime); - else if(eqPrimePrime.isPresent()) - eqPrimePrimeSet.addAll(unify(eqPrimePrime.get(), fc, false)); - else - eqPrimePrimeSet.addAll(unify(eqPrime, fc, false)); + } + else if(eqPrimePrime.isPresent()) { + Set> unifyres = unify(eqPrimePrime.get(), fc, false); + + eqPrimePrimeSet.addAll(unifyres); + } + else { + Set> unifyres = unify(eqPrime, fc, false); + + + eqPrimePrimeSet.addAll(unifyres); + } } - } + //Muss auskommentiert werden, wenn computeCartesianRecursive ANFANG + //} + //Muss auskommentiert werden, wenn computeCartesianRecursive ENDE /* * Step 6 b) Build the union over everything. @@ -221,10 +373,231 @@ public class TypeUnifyTask extends RecursiveTask>> { /* * Step 7: Filter empty sets; */ - return eqPrimePrimeSet.stream().filter(x -> isSolvedForm(x)).collect(Collectors.toCollection(HashSet::new)); - + eqPrimePrimeSet = eqPrimePrimeSet.stream().filter(x -> isSolvedForm(x) || this.isUndefinedPairSet(x)).collect(Collectors.toCollection(HashSet::new)); + if (!eqPrimePrimeSet.isEmpty() && !isUndefinedPairSetSet(eqPrimePrimeSet)) + writeLog("Result1 " + eqPrimePrimeSet.toString()); + return eqPrimePrimeSet; } + + + Set> computeCartesianRecursive(Set> fstElems, ArrayList>> topLevelSets, Set eq, IFiniteClosure fc, boolean parallel) { + //ArrayList>> remainingSets = new ArrayList<>(topLevelSets); + fstElems.addAll(topLevelSets.stream() + .filter(x -> x.size()==1) + .map(y -> y.stream().findFirst().get()) + .collect(Collectors.toCollection(HashSet::new))); + ArrayList>> remainingSets = topLevelSets.stream() + .filter(x -> x.size()>1) + .collect(Collectors.toCollection(ArrayList::new)); + if (remainingSets.isEmpty()) {//Alle Elemente sind 1-elementig + Set> result = unify2(fstElems, eq, fc, parallel); + return result; + } + Set> nextSet = remainingSets.remove(0); + writeLog("nextSet: " + nextSet.toString()); + List> nextSetasList =new ArrayList<>(nextSet); + try { + //List> + //nextSetasList = oup.sortedCopy(nextSet);//new ArrayList<>(nextSet); + } + catch (java.lang.IllegalArgumentException e) { + System.out.print(""); + } + Set> result = new HashSet<>(); + int variance = 0; + Optional xi = nextSetasList.stream().map(x -> x.stream().filter(y -> y.getLhsType() instanceof PlaceholderType) + .filter(z -> ((PlaceholderType)z.getLhsType()).getVariance() != 0) + .map(c -> ((PlaceholderType)c.getLhsType()).getVariance()) + .reduce((a,b)-> {if (a==b) return a; else return 0; })) + .filter(d -> d.isPresent()) + .map(e -> e.get()) + .findAny(); + if (xi.isPresent()) { + variance = xi.get(); + } + //if (variance == 1 && nextSetasList.size() > 1) { + // List> al = new ArrayList<>(nextSetasList.size()); + // for (int ii = 0; ii < nextSetasList.size();ii++) { + // al.add(0,nextSetasList.get(ii)); + // } + // nextSetasList = al; + //} + //Set a = nextSetasListIt.next(); + /*if (nextSetasList.size()>1) {zu loeschen + if (nextSetasList.iterator().next().iterator().next().getLhsType().getName().equals("D")) + System.out.print(""); + if (variance == 1) { + a_next = oup.max(nextSetasList.iterator()); + } + else if (variance == -1) { + a_next = oup.min(nextSetasList.iterator()); + } + else if (variance == 0) { + a_next = nextSetasList.iterator().next(); + } + } + else { + a_next = nextSetasList.iterator().next(); + } + */ + if (!nextSetasList.iterator().hasNext()) + System.out.print(""); + if (nextSetasList.iterator().next().stream().filter(x -> x.getLhsType().getName().equals("D")).findFirst().isPresent() && nextSetasList.size()>1) + System.out.print(""); + while (nextSetasList.size() > 0) { //(nextSetasList.size() != 0) { + Set a = null; + if (variance == 1) { + a = oup.max(nextSetasList.iterator()); + nextSetasList.remove(a); + } + else if (variance == -1) { + a = oup.min(nextSetasList.iterator()); + nextSetasList.remove(a); + } + else if (variance == 0) { + a = nextSetasList.remove(0); + } + //writeLog("nextSet: " + nextSetasList.toString()+ "\n"); + //nextSetasList.remove(a); + /* zu loeschen + if (nextSetasList.size() > 0) { + if (nextSetasList.size()>1) { + if (variance == 1) { + a_next = oup.max(nextSetasList.iterator()); + } + else if (variance == -1) { + a_next = oup.min(nextSetasList.iterator()); + } + else { + a_next = nextSetasList.iterator().next(); + } + } + else { + a_next = nextSetasList.iterator().next(); + } + } + */ + //PL 2018-03-01 + //TODO: 1. Maximum und Minimum unterscheiden + //TODO: 2. compare noch für alle Elmemente die nicht X =. ty sind erweitern + //for(Set a : newSet) { + i++; + Set> elems = new HashSet>(fstElems); + elems.add(a); + //if (remainingSets.isEmpty()) {//muss immer gegeben sein, weil nur 1 Element der topLevelSets mehr als ein Elemet enthaelt + Set> res = unify2(elems, eq, fc, parallel); + if (!isUndefinedPairSetSet(res) && isUndefinedPairSetSet(result)) { + //wenn korrektes Ergebnis gefunden alle Fehlerfaelle loeschen + result = res; + } + else { + if ((isUndefinedPairSetSet(res) && isUndefinedPairSetSet(result)) + || (!isUndefinedPairSetSet(res) && !isUndefinedPairSetSet(result)) + || result.isEmpty()) { + //alle Fehlerfaelle und alle korrekten Ergebnis jeweils adden + result.addAll(res); + } + //else { + //wenn Korrekte Ergebnisse da und Feherfälle dazukommen Fehlerfälle ignorieren + // if (isUndefinedPairSetSet(res) && !isUndefinedPairSetSet(result)) { + // result = result; + // } + //} + } + + //} + //else {//duerfte gar nicht mehr vorkommen PL 2018-04-03 + //result.addAll(computeCartesianRecursive(elems, remainingSets, eq, fc, parallel)); + //} + + if (!result.isEmpty() && !isUndefinedPairSetSet(res)) { + if (nextSetasList.iterator().hasNext() && nextSetasList.iterator().next().stream().filter(x -> x.getLhsType().getName().equals("D")).findFirst().isPresent() && nextSetasList.size()>1) + System.out.print(""); + Iterator> nextSetasListIt = new ArrayList>(nextSetasList).iterator(); + if (variance == 1) { + System.out.println(""); + while (nextSetasListIt.hasNext()) { + Set a_next = nextSetasListIt.next(); + if (a.equals(a_next) || + (oup.compare(a, a_next) == 1)) { + nextSetasList.remove(a_next); + } + } + } + else { if (variance == -1) { + System.out.println(""); + while (nextSetasListIt.hasNext()) { + Set a_next = nextSetasListIt.next(); + if (a.equals(a_next) || + (oup.compare(a, a_next) == -1)) { + nextSetasList.remove(0); + } + } + } + else if (variance == 0) { + break; + } + } + } + if (isUndefinedPairSetSet(res)) { + Set abhSubst = res.stream() + .map(b -> + b.stream() + .map(x -> x.getAllSubstitutions()) + .reduce((y,z) -> { y.addAll(z); return y;}).get()) + .reduce((y,z) -> { y.addAll(z); return y;}).get(); + Set b = a;//effective final a + Set durchschnitt = abhSubst.stream() + .filter(x -> b.contains(x)) + //.filter(y -> abhSubst.contains(y)) + .collect(Collectors.toCollection(HashSet::new)); + Set vars = durchschnitt.stream().map(x -> (PlaceholderType)x.getLhsType()).collect(Collectors.toCollection(HashSet::new)); + int len = nextSetasList.size(); + nextSetasList = nextSetasList.stream().filter(x -> { + //Boolean ret = false; + //for (PlaceholderType var : vars) { + // ret = ret || x.stream().map(b -> b.getLhsType().equals(var)).reduce((c,d) -> c || d).get(); + //} + return (!x.containsAll(durchschnitt)); + }).collect(Collectors.toCollection(ArrayList::new)); + writeLog("abhSubst: " + abhSubst.toString()); + writeLog("a: " + a.toString()); + writeLog("Durchschnitt: " + durchschnitt.toString()); + writeLog("nextSet: " + nextSet.toString()); + writeLog("nextSetasList: " + nextSetasList.toString()); + writeLog("Number erased Elements (undef): " + (len - nextSetasList.size())); + noAllErasedElements = noAllErasedElements + (len - nextSetasList.size()); + writeLog("Number erased Elements (undef): " + noAllErasedElements.toString()); + noBacktracking++; + writeLog("Number of Backtracking: " + noBacktracking); + System.out.println(""); + } + //if (nextSetasList.size() == 0 && isUndefinedPairSetSet(result) && nextSet.size() > 1) { + // return result; + //} + //else { + // result.removeIf(y -> isUndefinedPairSet(y)); + //} + //else result.stream().filter(y -> !isUndefinedPairSet(y)); + } + return result; + } + + + protected boolean isUndefinedPairSet(Set s) { + Boolean ret = s.stream().map(x -> x.isUndefinedPair()).reduce(true, (x,y)-> (x && y)); + return ret; + } + + protected boolean isUndefinedPairSetSet(Set> s) { + if (s.size() >= 1) { + Boolean ret = s.stream(). map(x -> isUndefinedPairSet(x)).reduce(true, (x,y)-> (x && y)); + return ret; + } + return false; + + } /** * Checks whether a set of pairs is in solved form. * @param eqPrimePrime The set of pair @@ -250,7 +623,7 @@ public class TypeUnifyTask extends RecursiveTask>> { * This is step one of the unification algorithm. * @return The set of pairs that results from repeated application of the inference rules. */ - protected Set applyTypeUnificationRules(Set eq, IFiniteClosure fc) { + public Set applyTypeUnificationRules(Set eq, IFiniteClosure fc) { /* * Rule Application Strategy: @@ -287,9 +660,10 @@ public class TypeUnifyTask extends RecursiveTask>> { opt = opt.isPresent() ? opt : rules.reduceWildcardLowRight(pair); opt = opt.isPresent() ? opt : rules.reduceWildcardUp(pair); opt = opt.isPresent() ? opt : rules.reduceWildcardUpRight(pair); - opt = opt.isPresent() ? opt : rules.reduceWildcardLowUp(pair); - opt = opt.isPresent() ? opt : rules.reduceWildcardUpLow(pair); - opt = opt.isPresent() ? opt : rules.reduceWildcardLeft(pair); + //PL 2018-03-06 auskommentiert muesste falsch sein vgl. JAVA_BSP/Wildcard6.java + //opt = opt.isPresent() ? opt : rules.reduceWildcardLowUp(pair); + //opt = opt.isPresent() ? opt : rules.reduceWildcardUpLow(pair); + //opt = opt.isPresent() ? opt : rules.reduceWildcardLeft(pair); // Reduce TPH opt = opt.isPresent() ? opt : rules.reduceTph(pair); @@ -301,6 +675,12 @@ public class TypeUnifyTask extends RecursiveTask>> { } // Reduce1, Reduce2, ReduceExt, ReduceSup, ReduceEq + //try { + // logFile.write("PAIR1 " + pair + "\n"); + // logFile.flush(); + //} + //catch (IOException e) { } + Optional> optSet = rules.reduce1(pair, fc); optSet = optSet.isPresent() ? optSet : rules.reduce2(pair); optSet = optSet.isPresent() ? optSet : rules.reduceExt(pair, fc); @@ -324,6 +704,11 @@ public class TypeUnifyTask extends RecursiveTask>> { } // Adapt, AdaptExt, AdaptSup + //try { + // logFile.write("PAIR2 " + pair + "\n"); + // logFile.flush(); + //} + //catch (IOException e) { } opt = rules.adapt(pair, fc); opt = opt.isPresent() ? opt : rules.adaptExt(pair, fc); opt = opt.isPresent() ? opt : rules.adaptSup(pair, fc); @@ -385,26 +770,77 @@ public class TypeUnifyTask extends RecursiveTask>> { // Init all 8 cases for(int i = 0; i < 8; i++) result.add(new HashSet<>()); - - for(UnifyPair pair : eq2s) { + ArrayList eq2sprime = new ArrayList<>(eq2s); + Iterator eq2sprimeit = eq2sprime.iterator(); + ArrayList eq2sAsList = new ArrayList<>(); + while(eq2sprimeit.hasNext()) {// alle mit Variance != 0 nach vorne schieben + UnifyPair up = eq2sprimeit.next(); + if ((up.getLhsType() instanceof PlaceholderType && ((PlaceholderType)up.getLhsType()).getVariance() != 0) + || (up.getRhsType() instanceof PlaceholderType && ((PlaceholderType)up.getRhsType()).getVariance() != 0)) { + eq2sAsList.add(up); + eq2s.remove(up); + } + } + eq2sAsList.addAll(eq2s); + Boolean first = true; + for(UnifyPair pair : eq2sAsList) { PairOperator pairOp = pair.getPairOp(); UnifyType lhsType = pair.getLhsType(); UnifyType rhsType = pair.getRhsType(); // Case 1: (a <. Theta') if(pairOp == PairOperator.SMALLERDOT && lhsType instanceof PlaceholderType) { - System.out.println(pair); - Set> x1 = unifyCase1((PlaceholderType) pair.getLhsType(), pair.getRhsType(), fc); - System.out.println(x1); - result.get(0).add(x1); + //System.out.println(pair); + if (first) { //writeLog(pair.toString()+"\n"); + Set> x1 = unifyCase1(pair, fc); + //System.out.println(x1); + result.get(0).add(x1); + if (x1.isEmpty()) { + undefined.add(pair); //Theta ist nicht im FC => Abbruch + } + } + else { + Set s1 = new HashSet<>(); + s1.add(pair); + Set> s2 = new HashSet<>(); + s2.add(s1); + result.get(0).add(s2); + } + } // Case 2: (a <.? ? ext Theta') else if(pairOp == PairOperator.SMALLERDOTWC && lhsType instanceof PlaceholderType && rhsType instanceof ExtendsType) - result.get(1).add(unifyCase2((PlaceholderType) pair.getLhsType(), (ExtendsType) pair.getRhsType(), fc)); + if (first) { //writeLog(pair.toString()+"\n"); + Set> x1 = unifyCase2(pair, fc); + result.get(1).add(x1); + if (x1.isEmpty()) { + undefined.add(pair); //Theta ist nicht im FC + } + } + else { + Set s1 = new HashSet<>(); + s1.add(pair); + Set> s2 = new HashSet<>(); + s2.add(s1); + result.get(1).add(s2); + } // Case 3: (a <.? ? sup Theta') else if(pairOp == PairOperator.SMALLERDOTWC && lhsType instanceof PlaceholderType && rhsType instanceof SuperType) - result.get(2).add(unifyCase3((PlaceholderType) lhsType, (SuperType) rhsType, fc)); + if (first) { //writeLog(pair.toString()+"\n"); + Set> x1 = unifyCase3(pair, fc); + result.get(2).add(x1); + if (x1.isEmpty()) { + undefined.add(pair); //Theta ist nicht im FC + } + } + else { + Set s1 = new HashSet<>(); + s1.add(pair); + Set> s2 = new HashSet<>(); + s2.add(s1); + result.get(2).add(s2); + } // Case 4 was replaced by an inference rule // Case 4: (a <.? Theta') @@ -413,7 +849,20 @@ public class TypeUnifyTask extends RecursiveTask>> { // Case 5: (Theta <. a) else if(pairOp == PairOperator.SMALLERDOT && rhsType instanceof PlaceholderType) - result.get(4).add(unifyCase5(lhsType, (PlaceholderType) rhsType, fc)); + if (first) { //writeLog(pair.toString()+"\n"); + Set> x1 = unifyCase5(pair, fc); + result.get(4).add(x1); + if (x1.isEmpty()) { + undefined.add(pair); //Theta ist nicht im FC + } + } + else { + Set s1 = new HashSet<>(); + s1.add(pair); + Set> s2 = new HashSet<>(); + s2.add(s1); + result.get(4).add(s2); + } // Case 6 was replaced by an inference rule. // Case 6: (? ext Theta <.? a) @@ -427,7 +876,20 @@ public class TypeUnifyTask extends RecursiveTask>> { // Case 8: (Theta <.? a) else if(pairOp == PairOperator.SMALLERDOTWC && rhsType instanceof PlaceholderType) - result.get(7).add(unifyCase8(lhsType, (PlaceholderType) rhsType, fc)); + if (first) { //writeLog(pair.toString()+"\n"); + Set> x1 = unifyCase8(pair, fc); + result.get(7).add(x1); + if (x1.isEmpty()) { + undefined.add(pair); //Theta ist nicht im FC + } + } + else { + Set s1 = new HashSet<>(); + s1.add(pair); + Set> s2 = new HashSet<>(); + s2.add(s1); + result.get(7).add(s2); + } // Case unknown: If a pair fits no other case, then the type unification has failed. // Through application of the rules, every pair should have one of the above forms. // Pairs that do not have one of the aboves form are contradictory. @@ -436,6 +898,7 @@ public class TypeUnifyTask extends RecursiveTask>> { undefined.add(pair); break; } + first = false; } // Filter empty sets or sets that only contain an empty set. @@ -443,10 +906,15 @@ public class TypeUnifyTask extends RecursiveTask>> { .filter(x -> x.size() > 0).collect(Collectors.toCollection(HashSet::new)); } + //TODO: Wenn Theta' nicht im FC muss ein Fehler produziert werden PL 18-04-20 /** * Cartesian product Case 1: (a <. Theta') */ - protected Set> unifyCase1(PlaceholderType a, UnifyType thetaPrime, IFiniteClosure fc) { + protected Set> unifyCase1(UnifyPair pair, IFiniteClosure fc) { + PlaceholderType a = (PlaceholderType)pair.getLhsType(); + UnifyType thetaPrime = pair.getRhsType(); + byte variance = pair.getVariance(); + Set> result = new HashSet<>(); boolean allGen = thetaPrime.getTypeParams().size() > 0; @@ -458,11 +926,23 @@ public class TypeUnifyTask extends RecursiveTask>> { Set cs = fc.getAllTypesByName(thetaPrime.getName());//cs= [java.util.Vector, java.util.Vector>, ????java.util.Vector???] + + //PL 18-02-06 entfernt, kommt durch unify wieder rein //cs.add(thetaPrime); //PL 18-02-06 entfernt - for(UnifyType c : cs) { + //cs muessen fresh Typvars gesetzt werden PL 2018-03-18 + Set csPHRenamed = cs.stream().map(x -> { + BinaryOperator> combiner = (aa,b) -> { aa.putAll(b); return aa;}; + HashMap hm = x.getInvolvedPlaceholderTypes().stream() + .reduce(new HashMap(), + (aa, b)-> { aa.put(b,PlaceholderType.freshPlaceholder()); return aa; }, combiner); + return x.accept(new freshPlaceholder(), hm); + }).collect(Collectors.toCollection(HashSet::new)); + + + for(UnifyType c : csPHRenamed) { //PL 18-02-05 getChildren durch smaller ersetzt in getChildren werden die Varianlen nicht ersetzt. Set thetaQs = fc.smaller(c).stream().collect(Collectors.toCollection(HashSet::new)); //Set thetaQs = fc.getChildren(c).stream().collect(Collectors.toCollection(HashSet::new)); @@ -489,24 +969,36 @@ public class TypeUnifyTask extends RecursiveTask>> { } for(UnifyType tqp : thetaQPrimes) { - //System.out.println(tqp.toString()); - //i++; - //System.out.println(i); - //if (i == 62) - // System.out.println(tqp.toString()); Optional opt = stdUnify.unify(tqp, thetaPrime); - if (!opt.isPresent()) + if (!opt.isPresent()) { continue; - + } + Unifier unifier = opt.get(); unifier.swapPlaceholderSubstitutions(thetaPrime.getTypeParams()); Set substitutionSet = new HashSet<>(); - for (Entry sigma : unifier) - substitutionSet.add(new UnifyPair(sigma.getKey(), sigma.getValue(), PairOperator.EQUALSDOT)); - + for (Entry sigma : unifier) { + substitutionSet.add(new UnifyPair(sigma.getKey(), sigma.getValue(), PairOperator.EQUALSDOT, + //TODO: nochmals ueberlegen ob hier pair.getSubstitution() korrekt ist, oder ob leere Menge hin müsste + //alle folgenden New UnifyPair ebenfalls ueberpruefen PL 2018-04-19 + pair.getSubstitution(), pair)); + } //List freshTphs = new ArrayList<>(); PL 18-02-06 in die For-Schleife verschoben for (UnifyType tq : thetaQs) { Set smaller = fc.smaller(unifier.apply(tq)); + //eingefuegt PL 2018-03-29 Anfang ? ext. theta hinzufuegen + if (a.isWildcardable()) { + Set smaller_ext = smaller.stream().filter(x -> !(x instanceof ExtendsType) && !(x instanceof SuperType)) + .map(x -> { + //BinaryOperator> combiner = (aa,b) -> { aa.putAll(b); return aa;}; //Variablenumbenennung rausgenommen + //HashMap hm = x.getInvolvedPlaceholderTypes().stream() //Variablen muessen wahrscheinlich erhalten bleiben + // .reduce(new HashMap(), + // (aa, b)-> { aa.put(b,PlaceholderType.freshPlaceholder()); return aa; }, combiner); + return new ExtendsType (x);})//.accept(new freshPlaceholder(), hm));} + .collect(Collectors.toCollection(HashSet::new)); + smaller.addAll(smaller_ext); + } + //eingefuegt PL 2018-03-29 Ende ? ext. theta hinzufuegen for(UnifyType theta : smaller) { List freshTphs = new ArrayList<>(); Set resultPrime = new HashSet<>(); @@ -514,15 +1006,27 @@ public class TypeUnifyTask extends RecursiveTask>> { for(int i = 0; !allGen && i < theta.getTypeParams().size(); i++) { if(freshTphs.size()-1 < i) freshTphs.add(PlaceholderType.freshPlaceholder()); - resultPrime.add(new UnifyPair(freshTphs.get(i), theta.getTypeParams().get(i), PairOperator.SMALLERDOTWC)); + resultPrime.add(new UnifyPair(freshTphs.get(i), theta.getTypeParams().get(i), PairOperator.SMALLERDOTWC, pair.getSubstitution(), pair)); } - if(allGen) - resultPrime.add(new UnifyPair(a, theta, PairOperator.EQUALSDOT)); - else - resultPrime.add(new UnifyPair(a, theta.setTypeParams(new TypeParams(freshTphs.toArray(new UnifyType[0]))), PairOperator.EQUALSDOT)); + if(allGen) { + UnifyPair up = new UnifyPair(a, theta, PairOperator.EQUALSDOT, pair.getSubstitution(), pair); + Iterator upit = up.getRhsType().getTypeParams().iterator(); + while (upit.hasNext()) ((PlaceholderType)upit.next()).setVariance(a.getVariance()); + resultPrime.add(up); + } + else { + UnifyPair up = new UnifyPair(a, theta.setTypeParams(new TypeParams(freshTphs.toArray(new UnifyType[0]))), PairOperator.EQUALSDOT, pair.getSubstitution(), pair); + Iterator upit = up.getRhsType().getTypeParams().iterator(); + while (upit.hasNext()) ((PlaceholderType)upit.next()).setVariance(a.getVariance()); + resultPrime.add(up); + } resultPrime.addAll(substitutionSet); + //writeLog("Substitution: " + substitutionSet.toString()); + resultPrime = resultPrime.stream().map(x -> { x.setVariance(variance); return x;}).collect(Collectors.toCollection(HashSet::new)); result.add(resultPrime); + //writeLog("Result: " + resultPrime.toString()); + //writeLog("MAX: " + oup.max(resultPrime.iterator()).toString()); } } @@ -535,40 +1039,53 @@ public class TypeUnifyTask extends RecursiveTask>> { /** * Cartesian Product Case 2: (a <.? ? ext Theta') */ - private Set> unifyCase2(PlaceholderType a, ExtendsType extThetaPrime, IFiniteClosure fc) { + private Set> unifyCase2(UnifyPair pair, IFiniteClosure fc) { + PlaceholderType a = (PlaceholderType) pair.getLhsType(); + ExtendsType extThetaPrime = (ExtendsType) pair.getRhsType(); + byte variance = pair.getVariance(); Set> result = new HashSet<>(); UnifyType aPrime = PlaceholderType.freshPlaceholder(); + ((PlaceholderType)aPrime).setVariance(((PlaceholderType)a).getVariance()); UnifyType extAPrime = new ExtendsType(aPrime); UnifyType thetaPrime = extThetaPrime.getExtendedType(); Set resultPrime = new HashSet<>(); - resultPrime.add(new UnifyPair(a, thetaPrime, PairOperator.SMALLERDOT)); + resultPrime.add(new UnifyPair(a, thetaPrime, PairOperator.SMALLERDOT, pair.getSubstitution(), pair)); result.add(resultPrime); resultPrime = new HashSet<>(); - resultPrime.add(new UnifyPair(a, extAPrime, PairOperator.EQUALSDOT)); - resultPrime.add(new UnifyPair(aPrime, thetaPrime, PairOperator.SMALLERDOT)); + resultPrime.add(new UnifyPair(a, extAPrime, PairOperator.EQUALSDOT, pair.getSubstitution(), pair)); + resultPrime.add(new UnifyPair(aPrime, thetaPrime, PairOperator.SMALLERDOT, pair.getSubstitution(), pair)); + resultPrime = resultPrime.stream().map(x -> { x.setVariance(variance); return x;}).collect(Collectors.toCollection(HashSet::new)); result.add(resultPrime); + //writeLog("Result: " + resultPrime.toString()); return result; } /** * Cartesian Product Case 3: (a <.? ? sup Theta') */ - private Set> unifyCase3(PlaceholderType a, SuperType subThetaPrime, IFiniteClosure fc) { + private Set> unifyCase3(UnifyPair pair, IFiniteClosure fc) { + PlaceholderType a = (PlaceholderType) pair.getLhsType(); + SuperType subThetaPrime = (SuperType) pair.getRhsType(); + byte variance = pair.getVariance(); Set> result = new HashSet<>(); UnifyType aPrime = PlaceholderType.freshPlaceholder(); + ((PlaceholderType)aPrime).setVariance(((PlaceholderType)a).getVariance()); UnifyType supAPrime = new SuperType(aPrime); UnifyType thetaPrime = subThetaPrime.getSuperedType(); Set resultPrime = new HashSet<>(); - resultPrime.add(new UnifyPair(thetaPrime, a, PairOperator.SMALLERDOT)); + resultPrime.add(new UnifyPair(thetaPrime, a, PairOperator.SMALLERDOT, pair.getSubstitution(), pair)); result.add(resultPrime); + //writeLog(resultPrime.toString()); resultPrime = new HashSet<>(); - resultPrime.add(new UnifyPair(a, supAPrime, PairOperator.EQUALSDOT)); - resultPrime.add(new UnifyPair(thetaPrime, aPrime, PairOperator.SMALLERDOT)); + resultPrime.add(new UnifyPair(a, supAPrime, PairOperator.EQUALSDOT, pair.getSubstitution(), pair)); + resultPrime.add(new UnifyPair(thetaPrime, aPrime, PairOperator.SMALLERDOT, pair.getSubstitution(), pair)); + resultPrime = resultPrime.stream().map(x -> { x.setVariance(variance); return x;}).collect(Collectors.toCollection(HashSet::new)); result.add(resultPrime); + //writeLog(resultPrime.toString()); return result; } @@ -576,7 +1093,10 @@ public class TypeUnifyTask extends RecursiveTask>> { /** * Cartesian Product Case 5: (Theta <. a) */ - private Set> unifyCase5(UnifyType theta, PlaceholderType a, IFiniteClosure fc) { + private Set> unifyCase5(UnifyPair pair, IFiniteClosure fc) { + UnifyType theta = pair.getLhsType(); + PlaceholderType a = (PlaceholderType) pair.getRhsType(); + byte variance = pair.getVariance(); Set> result = new HashSet<>(); boolean allGen = theta.getTypeParams().size() > 0; @@ -592,14 +1112,17 @@ public class TypeUnifyTask extends RecursiveTask>> { UnifyType[] freshTphs = new UnifyType[thetaS.getTypeParams().size()]; for(int i = 0; !allGen && i < freshTphs.length; i++) { freshTphs[i] = PlaceholderType.freshPlaceholder(); - resultPrime.add(new UnifyPair(thetaS.getTypeParams().get(i), freshTphs[i], PairOperator.SMALLERDOTWC)); + ((PlaceholderType)freshTphs[i]).setVariance(((PlaceholderType)a).getVariance()); + resultPrime.add(new UnifyPair(thetaS.getTypeParams().get(i), freshTphs[i], PairOperator.SMALLERDOTWC, pair.getSubstitution(), pair)); } if(allGen) - resultPrime.add(new UnifyPair(a, thetaS, PairOperator.EQUALSDOT)); + resultPrime.add(new UnifyPair(a, thetaS, PairOperator.EQUALSDOT, pair.getSubstitution(), pair)); else - resultPrime.add(new UnifyPair(a, thetaS.setTypeParams(new TypeParams(freshTphs)), PairOperator.EQUALSDOT)); + resultPrime.add(new UnifyPair(a, thetaS.setTypeParams(new TypeParams(freshTphs)), PairOperator.EQUALSDOT, pair.getSubstitution(), pair)); + resultPrime = resultPrime.stream().map(x -> { x.setVariance(variance); return x;}).collect(Collectors.toCollection(HashSet::new)); result.add(resultPrime); + //writeLog(resultPrime.toString()); } return result; @@ -608,23 +1131,32 @@ public class TypeUnifyTask extends RecursiveTask>> { /** * Cartesian Product Case 8: (Theta <.? a) */ - private Set> unifyCase8(UnifyType theta, PlaceholderType a, IFiniteClosure fc) { + private Set> unifyCase8(UnifyPair pair, IFiniteClosure fc) { + UnifyType theta = pair.getLhsType(); + PlaceholderType a = (PlaceholderType) pair.getRhsType(); + byte variance = pair.getVariance(); Set> result = new HashSet<>(); //for(UnifyType thetaS : fc.grArg(theta)) { Set resultPrime = new HashSet<>(); - resultPrime.add(new UnifyPair(a, theta, PairOperator.EQUALSDOT)); + resultPrime.add(new UnifyPair(a, theta, PairOperator.EQUALSDOT, pair.getSubstitution(), pair)); result.add(resultPrime); + //writeLog(resultPrime.toString()); UnifyType freshTph = PlaceholderType.freshPlaceholder(); + + ((PlaceholderType)freshTph).setVariance(a.getVariance()); resultPrime = new HashSet<>(); - resultPrime.add(new UnifyPair(a, new ExtendsType(freshTph), PairOperator.EQUALSDOT)); - resultPrime.add(new UnifyPair(theta, freshTph, PairOperator.SMALLERDOT)); + resultPrime.add(new UnifyPair(a, new ExtendsType(freshTph), PairOperator.EQUALSDOT, pair.getSubstitution(), pair)); + resultPrime.add(new UnifyPair(theta, freshTph, PairOperator.SMALLERDOT, pair.getSubstitution(), pair)); result.add(resultPrime); + //writeLog(resultPrime.toString()); resultPrime = new HashSet<>(); - resultPrime.add(new UnifyPair(a, new SuperType(freshTph), PairOperator.EQUALSDOT)); - resultPrime.add(new UnifyPair(freshTph, theta, PairOperator.SMALLERDOT)); + resultPrime.add(new UnifyPair(a, new SuperType(freshTph), PairOperator.EQUALSDOT, pair.getSubstitution(), pair)); + resultPrime.add(new UnifyPair(freshTph, theta, PairOperator.SMALLERDOT, pair.getSubstitution(), pair)); + resultPrime = resultPrime.stream().map(x -> { x.setVariance(variance); return x;}).collect(Collectors.toCollection(HashSet::new)); result.add(resultPrime); + //writeLog(resultPrime.toString()); //} return result; @@ -662,4 +1194,13 @@ public class TypeUnifyTask extends RecursiveTask>> { permuteParams(candidates, idx+1, result, current); } } + + void writeLog(String str) { + try { + logFile.write(str+"\n"); + logFile.flush(); + + } + catch (IOException e) { } + } } diff --git a/src/de/dhbwstuttgart/typeinference/unify/distributeVariance.java b/src/de/dhbwstuttgart/typeinference/unify/distributeVariance.java new file mode 100644 index 00000000..1779c941 --- /dev/null +++ b/src/de/dhbwstuttgart/typeinference/unify/distributeVariance.java @@ -0,0 +1,54 @@ +package de.dhbwstuttgart.typeinference.unify; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +import de.dhbwstuttgart.typeinference.unify.model.FunNType; +import de.dhbwstuttgart.typeinference.unify.model.PlaceholderType; +import de.dhbwstuttgart.typeinference.unify.model.TypeParams; +import de.dhbwstuttgart.typeinference.unify.model.UnifyType; + +public class distributeVariance extends visitUnifyTypeVisitor { + + public static int inverseVariance(int variance) { + Integer ret = 0; + if (variance == 1) { + ret = -1; + } + if (variance == -1) { + ret = 1; + } + return ret; + } + + + @Override + public PlaceholderType visit(PlaceholderType phty, Integer ht) { + if (ht != 0) { + if (phty.getVariance() == 0) { + phty.setVariance(ht); + } + //PL 2018-05-17 urspruengliche Variance nicht veraendern + //else if (phty.getVariance() != ht) { + // phty.setVariance(0); + //} + } + return phty; + } + + public FunNType visit(FunNType funnty, Integer ht) { + List param = new ArrayList<>(funnty.getTypeParams().get().length); + param.addAll(Arrays.asList(funnty.getTypeParams().get())); + UnifyType resultType = param.remove(param.size()-1); + Integer htInverse = inverseVariance(ht); + param = param.stream() + .map(x -> x.accept(this, htInverse)) + .collect(Collectors.toCollection(ArrayList::new)); + param.add(resultType.accept(this, ht)); + return FunNType.getFunNType(new TypeParams(param)); + } + + +} diff --git a/src/de/dhbwstuttgart/typeinference/unify/freshPlaceholder.java b/src/de/dhbwstuttgart/typeinference/unify/freshPlaceholder.java new file mode 100644 index 00000000..69870bd5 --- /dev/null +++ b/src/de/dhbwstuttgart/typeinference/unify/freshPlaceholder.java @@ -0,0 +1,15 @@ +package de.dhbwstuttgart.typeinference.unify; + + +import java.util.HashMap; + +import de.dhbwstuttgart.typeinference.unify.model.PlaceholderType; + + +public class freshPlaceholder extends visitUnifyTypeVisitor> { + + @Override + public PlaceholderType visit(PlaceholderType phty, HashMap ht) { + return ht.get(phty); + } +} diff --git a/src/de/dhbwstuttgart/typeinference/unify/interfaces/IFiniteClosure.java b/src/de/dhbwstuttgart/typeinference/unify/interfaces/IFiniteClosure.java index dcb6c4d1..e97a40e8 100644 --- a/src/de/dhbwstuttgart/typeinference/unify/interfaces/IFiniteClosure.java +++ b/src/de/dhbwstuttgart/typeinference/unify/interfaces/IFiniteClosure.java @@ -5,6 +5,7 @@ import java.util.Set; import de.dhbwstuttgart.typeinference.unify.model.ExtendsType; import de.dhbwstuttgart.typeinference.unify.model.FunNType; +import de.dhbwstuttgart.typeinference.unify.model.PairOperator; import de.dhbwstuttgart.typeinference.unify.model.PlaceholderType; import de.dhbwstuttgart.typeinference.unify.model.ReferenceType; import de.dhbwstuttgart.typeinference.unify.model.SuperType; @@ -60,5 +61,7 @@ public interface IFiniteClosure { public Optional getLeftHandedType(String typeName); public Set getAncestors(UnifyType t); public Set getChildren(UnifyType t); - public Set getAllTypesByName(String typeName); + public Set getAllTypesByName(String typeName); + + public int compare(UnifyType rhsType, UnifyType rhsType2, PairOperator pairop); } diff --git a/src/de/dhbwstuttgart/typeinference/unify/interfaces/IMatch.java b/src/de/dhbwstuttgart/typeinference/unify/interfaces/IMatch.java index 5e201dd7..ab88f33b 100644 --- a/src/de/dhbwstuttgart/typeinference/unify/interfaces/IMatch.java +++ b/src/de/dhbwstuttgart/typeinference/unify/interfaces/IMatch.java @@ -13,23 +13,17 @@ import de.dhbwstuttgart.typeinference.unify.model.UnifyPair; /** * Match * @author Martin Pluemicke + * abgeleitet aus IUnify.java */ public interface IMatch { /** - * Finds the most general unifier sigma of the set {t1,...,tn} so that - * sigma(t1) = sigma(t2) = ... = sigma(tn). - * @param terms The set of terms to be unified - * @return An optional of the most general unifier if it exists or an empty optional if there is no unifier. + * Finds the most general matcher sigma of the set {t1 =. t1',...,tn =. tn'} so that + * sigma(t1) = t1' , ... sigma(tn) = tn'. + * @param terms The set of terms to be matched + * @return An optional of the most general matcher if it exists or an empty optional if there is no matcher. */ public Optional match(ArrayList termsList); - - /** - * Finds the most general unifier sigma of the set {t1,...,tn} so that - * sigma(t1) = sigma(t2) = ... = sigma(tn). - * @param terms The set of terms to be unified - * @return An optional of the most general unifier if it exists or an empty optional if there is no unifier. - */ } diff --git a/src/de/dhbwstuttgart/typeinference/unify/interfaces/IRuleSet.java b/src/de/dhbwstuttgart/typeinference/unify/interfaces/IRuleSet.java index 62c9649f..a2b647c6 100644 --- a/src/de/dhbwstuttgart/typeinference/unify/interfaces/IRuleSet.java +++ b/src/de/dhbwstuttgart/typeinference/unify/interfaces/IRuleSet.java @@ -27,9 +27,13 @@ public interface IRuleSet { public Optional reduceWildcardLowRight(UnifyPair pair); public Optional reduceWildcardUp(UnifyPair pair); public Optional reduceWildcardUpRight(UnifyPair pair); + + /* + * vgl. JAVA_BSP/Wildcard6.java public Optional reduceWildcardLowUp(UnifyPair pair); public Optional reduceWildcardUpLow(UnifyPair pair); public Optional reduceWildcardLeft(UnifyPair pair); + */ /* * Additional Rules which replace cases of the cartesian product diff --git a/src/de/dhbwstuttgart/typeinference/unify/interfaces/IUnify.java b/src/de/dhbwstuttgart/typeinference/unify/interfaces/IUnify.java index 524608f5..57b41736 100644 --- a/src/de/dhbwstuttgart/typeinference/unify/interfaces/IUnify.java +++ b/src/de/dhbwstuttgart/typeinference/unify/interfaces/IUnify.java @@ -15,16 +15,16 @@ import de.dhbwstuttgart.typeinference.unify.model.Unifier; public interface IUnify { /** - * Finds the most general unifier sigma of the set {t1,...,tn} so that - * sigma(t1) = sigma(t2) = ... = sigma(tn). + * Finds the most general unifier sigma of the set {t1 =. t1',...,tn =. tn'} so that + * sigma(t1) = sigma(t1') , ... sigma(tn) = sigma(tn'). * @param terms The set of terms to be unified * @return An optional of the most general unifier if it exists or an empty optional if there is no unifier. */ public Optional unify(Set terms); /** - * Finds the most general unifier sigma of the set {t1,...,tn} so that - * sigma(t1) = sigma(t2) = ... = sigma(tn). + * Finds the most general unifier sigma of the set {t1 =. t1',...,tn =. tn'} so that + * sigma(t1) = sigma(t1') , ... sigma(tn) = sigma(tn'). * @param terms The set of terms to be unified * @return An optional of the most general unifier if it exists or an empty optional if there is no unifier. */ diff --git a/src/de/dhbwstuttgart/typeinference/unify/interfaces/UnifyTypeVisitor.java b/src/de/dhbwstuttgart/typeinference/unify/interfaces/UnifyTypeVisitor.java new file mode 100644 index 00000000..8d06b3e1 --- /dev/null +++ b/src/de/dhbwstuttgart/typeinference/unify/interfaces/UnifyTypeVisitor.java @@ -0,0 +1,23 @@ +package de.dhbwstuttgart.typeinference.unify.interfaces; + +import java.util.HashMap; + +import de.dhbwstuttgart.typeinference.unify.model.ExtendsType; +import de.dhbwstuttgart.typeinference.unify.model.FunNType; +import de.dhbwstuttgart.typeinference.unify.model.PlaceholderType; +import de.dhbwstuttgart.typeinference.unify.model.ReferenceType; +import de.dhbwstuttgart.typeinference.unify.model.SuperType; + +public interface UnifyTypeVisitor { + + public ReferenceType visit(ReferenceType refty, T ht); + + public PlaceholderType visit(PlaceholderType phty, T ht); + + public FunNType visit(FunNType funnty, T ht); + + public SuperType visit(SuperType suty, T ht); + + public ExtendsType visit(ExtendsType extty, T ht); + +} diff --git a/src/de/dhbwstuttgart/typeinference/unify/model/ExtendsType.java b/src/de/dhbwstuttgart/typeinference/unify/model/ExtendsType.java index 33f32e07..6c44d2ec 100644 --- a/src/de/dhbwstuttgart/typeinference/unify/model/ExtendsType.java +++ b/src/de/dhbwstuttgart/typeinference/unify/model/ExtendsType.java @@ -2,21 +2,30 @@ package de.dhbwstuttgart.typeinference.unify.model; import java.util.ArrayList; import java.util.Collection; +import java.util.HashMap; import java.util.Set; import de.dhbwstuttgart.typeinference.unify.interfaces.IFiniteClosure; +import de.dhbwstuttgart.typeinference.unify.interfaces.UnifyTypeVisitor; /** * An extends wildcard type "? extends T". */ public final class ExtendsType extends WildcardType { + public UnifyType accept(UnifyTypeVisitor visitor, T ht) { + return visitor.visit(this, ht); + } + /** * Creates a new extends wildcard type. * @param extendedType The extended type e.g. Integer in "? extends Integer" */ public ExtendsType(UnifyType extendedType) { - super("? extends " + extendedType.getName(), extendedType); + super("? extends " + extendedType.getName(), extendedType); + if (extendedType instanceof ExtendsType) { + System.out.print(""); + } } /** diff --git a/src/de/dhbwstuttgart/typeinference/unify/model/FiniteClosure.java b/src/de/dhbwstuttgart/typeinference/unify/model/FiniteClosure.java index dcffbee6..b45309b8 100644 --- a/src/de/dhbwstuttgart/typeinference/unify/model/FiniteClosure.java +++ b/src/de/dhbwstuttgart/typeinference/unify/model/FiniteClosure.java @@ -8,11 +8,14 @@ import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; -//PL 18-02-05 Unifier durch Matcher ersetzt -//mus greater noch erstezt werden +import com.google.common.collect.Ordering; + +//PL 18-02-05/18-04-05 Unifier durch Matcher ersetzt +//muss greater noch ersetzt werden ja erledigt 18--04-05 import de.dhbwstuttgart.typeinference.unify.MartelliMontanariUnify; import de.dhbwstuttgart.typeinference.unify.Match; +import de.dhbwstuttgart.typeinference.unify.TypeUnifyTask; import de.dhbwstuttgart.typeinference.unify.interfaces.IFiniteClosure; import de.dhbwstuttgart.typeinference.unify.interfaces.IUnify; @@ -20,7 +23,7 @@ import de.dhbwstuttgart.typeinference.unify.interfaces.IUnify; * The finite closure for the type unification * @author Florian Steurer */ -public class FiniteClosure implements IFiniteClosure { +public class FiniteClosure extends Ordering implements IFiniteClosure { /** * A map that maps every type to the node in the inheritance graph that contains that type. @@ -193,7 +196,9 @@ public class FiniteClosure implements IFiniteClosure { protected Set computeGreater(Set types) { HashSet result = new HashSet<>(); - IUnify unify = new MartelliMontanariUnify(); + //PL 18-04-05 Unifier durch Matcher ersetzt + //IUnify unify = new MartelliMontanariUnify(); + Match match = new Match(); for(UnifyType t : types) { @@ -215,7 +220,11 @@ public class FiniteClosure implements IFiniteClosure { Set> candidates = strInheritanceGraph.get(t.getName()); for(Node candidate : candidates) { UnifyType theta1 = candidate.getContent(); - Optional optSigma = unify.unify(theta1, t); + //PL 18-04-05 Unifier durch Matcher ersetzt ANFANG + ArrayList termList= new ArrayList(); + termList.add(new UnifyPair(theta1,t, PairOperator.EQUALSDOT)); + Optional optSigma = match.match(termList); + //PL 18-04-05 Unifier durch Matcher ersetzt ENDE if(!optSigma.isPresent()) continue; @@ -369,7 +378,7 @@ public class FiniteClosure implements IFiniteClosure { return Optional.empty(); for(UnifyPair pair : pairs) - if(pair.getLhsType().getName().equals(typeName)) + if(pair.getLhsType().getName().equals(typeName) && pair.getLhsType().typeParams.arePlaceholders()) return Optional.of(pair.getLhsType()); return Optional.empty(); @@ -430,4 +439,33 @@ public class FiniteClosure implements IFiniteClosure { public String toString(){ return this.inheritanceGraph.toString(); } + + public int compare (UnifyType left, UnifyType right) { + return compare(left, right, PairOperator.SMALLERDOT); + } + + public int compare (UnifyType left, UnifyType right, PairOperator pairop) { + if ((left instanceof ExtendsType && right instanceof ReferenceType) + || (right instanceof ExtendsType && left instanceof ReferenceType)) + System.out.println(""); + UnifyPair up = new UnifyPair(left, right, pairop); + TypeUnifyTask unifyTask = new TypeUnifyTask(); + HashSet hs = new HashSet<>(); + hs.add(up); + Set smallerRes = unifyTask.applyTypeUnificationRules(hs, this); + //Gleichungen der Form a <./=. Theta oder Theta <./=. a oder a <./=. b sind ok. + long smallerLen = smallerRes.stream().filter(x -> !(x.getLhsType() instanceof PlaceholderType || x.getRhsType() instanceof PlaceholderType)).count(); + if (smallerLen == 0) return -1; + else { + up = new UnifyPair(right, left, pairop); + //TypeUnifyTask unifyTask = new TypeUnifyTask(); + hs = new HashSet<>(); + hs.add(up); + Set greaterRes = unifyTask.applyTypeUnificationRules(hs, this); + //Gleichungen der Form a <./=. Theta oder Theta <./=. a oder a <./=. b sind ok. + long greaterLen = greaterRes.stream().filter(x -> !(x.getLhsType() instanceof PlaceholderType || x.getRhsType() instanceof PlaceholderType)).count(); + if (greaterLen == 0) return 1; + else return 0; + } + } } diff --git a/src/de/dhbwstuttgart/typeinference/unify/model/FunNType.java b/src/de/dhbwstuttgart/typeinference/unify/model/FunNType.java index cf2c86ae..95275a12 100644 --- a/src/de/dhbwstuttgart/typeinference/unify/model/FunNType.java +++ b/src/de/dhbwstuttgart/typeinference/unify/model/FunNType.java @@ -1,8 +1,12 @@ package de.dhbwstuttgart.typeinference.unify.model; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; import java.util.Set; import de.dhbwstuttgart.typeinference.unify.interfaces.IFiniteClosure; +import de.dhbwstuttgart.typeinference.unify.interfaces.UnifyTypeVisitor; /** * A real function type in java. @@ -10,6 +14,10 @@ import de.dhbwstuttgart.typeinference.unify.interfaces.IFiniteClosure; */ public class FunNType extends UnifyType { + public UnifyType accept(UnifyTypeVisitor visitor, T ht) { + return visitor.visit(this, ht); + } + /** * Creates a FunN-Type with the specified TypeParameters. */ @@ -67,11 +75,18 @@ public class FunNType extends UnifyType { return new FunNType(newParams); } + @Override + public Boolean wrongWildcard() { + return (new ArrayList(Arrays.asList(getTypeParams() + .get())).stream().filter(x -> (x instanceof WildcardType)).findFirst().isPresent()); + } + @Override public int hashCode() { return 181 + typeParams.hashCode(); } + @Override public boolean equals(Object obj) { if(!(obj instanceof FunNType)) diff --git a/src/de/dhbwstuttgart/typeinference/unify/model/OrderingUnifyPair.java b/src/de/dhbwstuttgart/typeinference/unify/model/OrderingUnifyPair.java new file mode 100644 index 00000000..8cebdd8a --- /dev/null +++ b/src/de/dhbwstuttgart/typeinference/unify/model/OrderingUnifyPair.java @@ -0,0 +1,228 @@ +package de.dhbwstuttgart.typeinference.unify.model; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.Optional; +import java.util.Set; +import java.util.function.BinaryOperator; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import com.google.common.collect.Ordering; + +import de.dhbwstuttgart.typeinference.unify.TypeUnifyTask; +import de.dhbwstuttgart.typeinference.unify.interfaces.IFiniteClosure; + + + +public class OrderingUnifyPair extends Ordering> { + + protected IFiniteClosure fc; + + public OrderingUnifyPair(IFiniteClosure fc) { + this.fc = fc; + } + + /* + * vergleicht Paare (a =. Theta) und (a =. Theta') + * in dem compare(Theta, Theta') aufgerufen wird. + */ + public int compareEq (UnifyPair left, UnifyPair right) { + if (left.getRhsType() instanceof WildcardType || right.getRhsType() instanceof WildcardType) { + return fc.compare(left.getRhsType(), right.getRhsType(), PairOperator.SMALLERDOTWC); + } + else { + return fc.compare(left.getRhsType(), right.getRhsType(), PairOperator.SMALLERDOT); + } + } + /* + public int compareEq (UnifyPair left, UnifyPair right) { + if (left == null || right == null) + System.out.println("Fehler"); + if (left.getLhsType() instanceof PlaceholderType) { + return fc.compare(left.getRhsType(), right.getRhsType(), left.getPairOp()); + } + else { + return fc.compare(left.getLhsType(), right.getLhsType(), left.getPairOp()); + } + } + */ + + public Pair> compare (UnifyType left, UnifyType right) { + UnifyPair up; + if (left instanceof WildcardType || right instanceof WildcardType) { + up = new UnifyPair(left, right, PairOperator.SMALLERDOTWC); + } + else { + up = new UnifyPair(left, right, PairOperator.SMALLERDOT); + } + TypeUnifyTask unifyTask = new TypeUnifyTask(); + HashSet hs = new HashSet<>(); + hs.add(up); + Set smallerRes = unifyTask.applyTypeUnificationRules(hs, fc); + long smallerLen = smallerRes.stream().filter(x -> !(x.getLhsType() instanceof PlaceholderType && x.getRhsType() instanceof PlaceholderType)).count(); + if (smallerLen == 0) return new Pair<>(-1, smallerRes); + else { + if (left instanceof WildcardType || right instanceof WildcardType) { + up = new UnifyPair(right, left, PairOperator.SMALLERDOTWC); + } + else { + up = new UnifyPair(right, left, PairOperator.SMALLERDOT); + } + //TypeUnifyTask unifyTask = new TypeUnifyTask(); + hs = new HashSet<>(); + hs.add(up); + Set greaterRes = unifyTask.applyTypeUnificationRules(hs, fc); + long greaterLen = greaterRes.stream().filter(x -> !(x.getLhsType() instanceof PlaceholderType && x.getRhsType() instanceof PlaceholderType)).count(); + if (greaterLen == 0) return new Pair<>(1, greaterRes); + else return new Pair<>(0, new HashSet<>()); + } + } + + /* TODO muss noch verifiziert werden PL 2018-03-21 + * (non-Javadoc) + * fuehrt zu Fehlern bei Arrays.sort (contract nicht erfuellt) + * @see com.google.common.collect.Ordering#compare(java.lang.Object, java.lang.Object) + */ + public int compare (Set left, Set right) { + Set lefteq = left.stream() + .filter(x -> (x.getLhsType() instanceof PlaceholderType && x.getPairOp() == PairOperator.EQUALSDOT)) + .collect(Collectors.toCollection(HashSet::new)); + Set righteq = right.stream() + .filter(x -> (x.getLhsType() instanceof PlaceholderType && x.getPairOp() == PairOperator.EQUALSDOT)) + .collect(Collectors.toCollection(HashSet::new)); + Set leftle = left.stream() + .filter(x -> ((x.getLhsType() instanceof PlaceholderType || x.getRhsType() instanceof PlaceholderType) + && x.getPairOp() == PairOperator.SMALLERDOT)) + .collect(Collectors.toCollection(HashSet::new)); + Set rightle = right.stream() + .filter(x -> ((x.getLhsType() instanceof PlaceholderType || x.getRhsType() instanceof PlaceholderType) + && x.getPairOp() == PairOperator.SMALLERDOT)) + .collect(Collectors.toCollection(HashSet::new)); + Set leftlewc = left.stream() + .filter(x -> ((x.getLhsType() instanceof PlaceholderType || x.getRhsType() instanceof PlaceholderType) + && x.getPairOp() == PairOperator.SMALLERDOTWC)) + .collect(Collectors.toCollection(HashSet::new)); + Set rightlewc = right.stream() + .filter(x -> ((x.getLhsType() instanceof PlaceholderType || x.getRhsType() instanceof PlaceholderType) + && x.getPairOp() == PairOperator.SMALLERDOTWC)) + .collect(Collectors.toCollection(HashSet::new)); + //System.out.println(left.toString()); + //Fall 2 und 3 + //if (lefteq.iterator().next().getLhsType().getName().equals("AJO")) { + // System.out.print(""); + //} + if (lefteq.size() == 1 && leftle.size() == 1 && righteq.size() == 0 && rightle.size() == 1) { + return 1; + } + //Fall 2 und 3 + if (lefteq.size() == 0 && leftle.size() == 1 && righteq.size() == 1 && rightle.size() == 1) { + return -1; + } + //Fall 5 + if (lefteq.size() == 1 && leftle.size() == 0 && righteq.size() == 1 && rightle.size() == 1) { + return -1; + } + //Fall 5 + if (lefteq.size() == 1 && leftle.size() == 1 && righteq.size() == 1 && rightle.size() == 0) { + return 1; + } + //Fall 5 + if (lefteq.size() == 1 && leftle.size() == 1 && righteq.size() == 1 && rightle.size() == 1) { + return 0; + } + // Nur Paare a =. Theta + if (leftle.size() == 0 && rightle.size() == 0 && leftlewc.size() == 0 && rightlewc.size() ==0) { + Stream lseq = lefteq.stream(); //left.filter(x -> (x.getLhsType() instanceof PlaceholderType && x.getPairOp() == PairOperator.EQUALSDOT)); + Stream rseq = righteq.stream(); //right.filter(x -> (x.getLhsType() instanceof PlaceholderType && x.getPairOp() == PairOperator.EQUALSDOT)); + BinaryOperator> combiner = (x,y) -> { x.putAll(y); return x;}; + HashMap hm = rseq.reduce(new HashMap(), (x, y)-> { x.put(y.getLhsType(),y); return x; }, combiner); + lseq = lseq.filter(x -> !(hm.get(x.getLhsType()) == null));//NOCHMALS UEBERPRUEFEN!!!! + lseq = lseq.filter(x -> !x.equals(hm.get(x.getLhsType()))); //Elemente die gleich sind muessen nicht verglichen werden + Optional si = lseq.map(x -> compareEq(x, hm.get(x.getLhsType()))).reduce((x,y)-> { if (x == y) return x; else return 0; } ); + if (!si.isPresent()) return 0; + else return si.get(); + } + //Fall 1 und 4 + if (lefteq.size() >= 1 && righteq.size() >= 1 && (leftlewc.size() > 0 || rightlewc.size() > 0)) { + if (lefteq.iterator().next().getLhsType().getName().equals("D")) + System.out.print(""); + //Set varsleft = lefteq.stream().map(x -> (PlaceholderType)x.getLhsType()).collect(Collectors.toCollection(HashSet::new)); + //Set varsright = righteq.stream().map(x -> (PlaceholderType)x.getLhsType()).collect(Collectors.toCollection(HashSet::new)); + //filtern des Paares a = Theta, das durch a <. Thata' generiert wurde (nur im Fall 1 relevant) + lefteq.removeIf(x -> !(x.getLhsType().getName().equals(x.getBasePair().getLhsType().getName()) + ||x.getLhsType().getName().equals(x.getBasePair().getRhsType().getName())));//removeIf(x -> !varsright.contains(x.getLhsType())); + righteq.removeIf(x -> !(x.getLhsType().getName().equals(x.getBasePair().getLhsType().getName()) + ||x.getLhsType().getName().equals(x.getBasePair().getRhsType().getName())));//.removeIf(x -> !varsleft.contains(x.getLhsType())); + UnifyPair lseq = lefteq.iterator().next(); + UnifyPair rseq = righteq.iterator().next(); + if (lseq.getRhsType().getName().equals("Object")) { + if (rseq.getRhsType().getName().equals("Object")) return 0; + else return 1; + } + else { + if (rseq.getRhsType().getName().equals("Object")) return -1; + } + if (leftlewc.size() == rightlewc.size()) { + //TODO: Hier wird bei Wildcards nicht das richtige compare aufgerufen PL 18-04-20 + Pair> int_Unifier = compare(lseq.getRhsType(), rseq.getRhsType()); + Unifier uni = new Unifier(); + int_Unifier.getValue().get().forEach(x -> uni.add((PlaceholderType) x.getLhsType(), x.getRhsType())); + if (!lseq.getRhsType().getName().equals(rseq.getRhsType().getName()) + || leftlewc.size() == 0 || rightlewc.size() == 0) return int_Unifier.getKey(); + else { + Set lsleuni = leftlewc.stream().map(x -> uni.apply(x)).collect(Collectors.toCollection(HashSet::new)); + Set rsleuni = rightlewc.stream().map(x -> uni.apply(x)).collect(Collectors.toCollection(HashSet::new)); + BinaryOperator> combiner = (x,y) -> { x.putAll(y); return x;}; + + HashMap hm; + Optional si; + //1. Fall + if (leftlewc.iterator().next().getLhsType() instanceof PlaceholderType) { + hm = rsleuni.stream().reduce(new HashMap(), (x, y)-> { x.put(y.getLhsType(),y); return x; }, combiner); + Stream lslewcstr = lsleuni.stream().filter(x -> !(hm.get(x.getLhsType()) == null)); + si = lslewcstr.map(x -> fc.compare(x.getRhsType(), hm.get(x.getLhsType()).getRhsType(), PairOperator.SMALLERDOTWC)).reduce((x,y)-> { if (x == y) return x; else return 0; } ); + } + //4. Fall + else { + hm = rsleuni.stream().reduce(new HashMap(), (x, y)-> { x.put(y.getRhsType(),y); return x; }, combiner); + Stream lslewcstr = lsleuni.stream().filter(x -> !(hm.get(x.getRhsType()) == null)); + si = lslewcstr.map(x -> fc.compare(x.getLhsType(), hm.get(x.getRhsType()).getLhsType(), PairOperator.SMALLERDOTWC)).reduce((x,y)-> { if (x == y) return x; else return 0; } ); + } + if (!si.isPresent()) return 0; + else return si.get(); + } + } else { + if (leftlewc.size() > 0) { + Set subst; + if (leftlewc.iterator().next().getLhsType() instanceof PlaceholderType) { + subst = leftlewc.stream().map(x -> new UnifyPair(x.getLhsType(), x.getRhsType(), PairOperator.EQUALSDOT)).collect(Collectors.toCollection(HashSet::new)); + } + else { + subst = leftlewc.stream().map(x -> new UnifyPair(x.getRhsType(), x.getLhsType(), PairOperator.EQUALSDOT)).collect(Collectors.toCollection(HashSet::new)); + } + Unifier uni = new Unifier(); + subst.stream().forEach(x -> uni.add((PlaceholderType) x.getLhsType(), x.getRhsType())); + lseq = uni.apply(lseq); + } + else { + Set subst; + if (rightlewc.iterator().next().getLhsType() instanceof PlaceholderType) { + subst = rightlewc.stream().map(x -> new UnifyPair(x.getLhsType(), x.getRhsType(), PairOperator.EQUALSDOT)).collect(Collectors.toCollection(HashSet::new)); + } + else { + subst = rightlewc.stream().map(x -> new UnifyPair(x.getRhsType(), x.getLhsType(), PairOperator.EQUALSDOT)).collect(Collectors.toCollection(HashSet::new)); + } + Unifier uni = new Unifier(); + subst.stream().forEach(x -> uni.add((PlaceholderType) x.getLhsType(), x.getRhsType())); + rseq = uni.apply(rseq); + } + return compareEq(lseq, rseq); + } + } + return 0; + } +} + diff --git a/src/de/dhbwstuttgart/typeinference/unify/model/Pair.java b/src/de/dhbwstuttgart/typeinference/unify/model/Pair.java new file mode 100644 index 00000000..08c4aa1c --- /dev/null +++ b/src/de/dhbwstuttgart/typeinference/unify/model/Pair.java @@ -0,0 +1,21 @@ +package de.dhbwstuttgart.typeinference.unify.model; + +import java.util.Optional; + +public class Pair { + private final T key; + private final T1 value; + + public Pair(T a, T1 b) { + this.value = b; + this.key = a; + } + + public Optional getValue() { + return Optional.of(value); + } + + public T getKey() { + return key; + } +} diff --git a/src/de/dhbwstuttgart/typeinference/unify/model/PlaceholderType.java b/src/de/dhbwstuttgart/typeinference/unify/model/PlaceholderType.java index e9268d0d..bbd3b3e1 100644 --- a/src/de/dhbwstuttgart/typeinference/unify/model/PlaceholderType.java +++ b/src/de/dhbwstuttgart/typeinference/unify/model/PlaceholderType.java @@ -2,11 +2,14 @@ package de.dhbwstuttgart.typeinference.unify.model; import java.util.ArrayList; import java.util.Collection; +import java.util.HashMap; import java.util.HashSet; import java.util.Random; import java.util.Set; +import de.dhbwstuttgart.typeinference.unify.distributeVariance; import de.dhbwstuttgart.typeinference.unify.interfaces.IFiniteClosure; +import de.dhbwstuttgart.typeinference.unify.interfaces.UnifyTypeVisitor; /** * An unbounded placeholder type. @@ -35,6 +38,21 @@ public final class PlaceholderType extends UnifyType{ */ private final boolean IsGenerated; + + /** + * isWildcardable gibt an, ob ein Wildcardtyp dem PlaceholderType zugeordnet werden darf + */ + private boolean wildcardable = true; + + /** + * variance shows the variance of the pair + * -1: contravariant + * 1 covariant + * 0 invariant + * PL 2018-03-21 + */ + private int variance = 0; + /** * Creates a new placeholder type with the specified name. */ @@ -54,6 +72,10 @@ public final class PlaceholderType extends UnifyType{ IsGenerated = isGenerated; } + public UnifyType accept(UnifyTypeVisitor visitor, T ht) { + return visitor.visit(this, ht); + } + /** * Creates a fresh placeholder type with a name that does so far not exist. * A user could later instantiate a type using the same name that is equivalent to this type. @@ -67,6 +89,7 @@ public final class PlaceholderType extends UnifyType{ return new PlaceholderType(name, true); } + /** * True if this placeholder is auto-generated, false if it is user-generated. */ @@ -74,6 +97,21 @@ public final class PlaceholderType extends UnifyType{ return IsGenerated; } + public void setVariance(int v) { + variance = v; + } + + public int getVariance() { + return variance; + } + + public Boolean isWildcardable() { + return wildcardable; + } + public void disableWildcardtable() { + wildcardable = false; + } + @Override Set smArg(IFiniteClosure fc) { return fc.smArg(this); @@ -96,8 +134,13 @@ public final class PlaceholderType extends UnifyType{ @Override UnifyType apply(Unifier unif) { - if(unif.hasSubstitute(this)) - return unif.getSubstitute(this); + if(unif.hasSubstitute(this)) { + UnifyType ret = unif.getSubstitute(this); + //PL 2018-05-17 Auskommentierung muesste korrekt sein, + //bereits in JavaTXComplier Variancen gesetzt werden. + //ret.accept(new distributeVariance(), this.getVariance()); + return ret; + } return this; } diff --git a/src/de/dhbwstuttgart/typeinference/unify/model/ReferenceType.java b/src/de/dhbwstuttgart/typeinference/unify/model/ReferenceType.java index 02ab38a0..81f6c3b3 100644 --- a/src/de/dhbwstuttgart/typeinference/unify/model/ReferenceType.java +++ b/src/de/dhbwstuttgart/typeinference/unify/model/ReferenceType.java @@ -1,8 +1,10 @@ package de.dhbwstuttgart.typeinference.unify.model; +import java.util.HashMap; import java.util.Set; import de.dhbwstuttgart.typeinference.unify.interfaces.IFiniteClosure; +import de.dhbwstuttgart.typeinference.unify.interfaces.UnifyTypeVisitor; /** * A reference type e.q. Integer or List. @@ -16,6 +18,11 @@ public final class ReferenceType extends UnifyType { */ private final int hashCode; + + public UnifyType accept(UnifyTypeVisitor visitor, T ht) { + return visitor.visit(this, ht); + } + public ReferenceType(String name, UnifyType... params) { super(name, new TypeParams(params)); hashCode = 31 + 17 * typeName.hashCode() + 17 * typeParams.hashCode(); diff --git a/src/de/dhbwstuttgart/typeinference/unify/model/SuperType.java b/src/de/dhbwstuttgart/typeinference/unify/model/SuperType.java index 4f78602f..53762f86 100644 --- a/src/de/dhbwstuttgart/typeinference/unify/model/SuperType.java +++ b/src/de/dhbwstuttgart/typeinference/unify/model/SuperType.java @@ -1,8 +1,10 @@ package de.dhbwstuttgart.typeinference.unify.model; +import java.util.HashMap; import java.util.Set; import de.dhbwstuttgart.typeinference.unify.interfaces.IFiniteClosure; +import de.dhbwstuttgart.typeinference.unify.interfaces.UnifyTypeVisitor; /** * A super wildcard type e.g. ? super Integer. @@ -10,6 +12,10 @@ import de.dhbwstuttgart.typeinference.unify.interfaces.IFiniteClosure; */ public final class SuperType extends WildcardType { + public UnifyType accept(UnifyTypeVisitor visitor, T ht) { + return visitor.visit(this, ht); + } + /** * Creates a new instance "? extends superedType" * @param superedType The type that is supered e.g. Integer in "? super Integer" diff --git a/src/de/dhbwstuttgart/typeinference/unify/model/TypeParams.java b/src/de/dhbwstuttgart/typeinference/unify/model/TypeParams.java index 3d5fc278..973a2785 100644 --- a/src/de/dhbwstuttgart/typeinference/unify/model/TypeParams.java +++ b/src/de/dhbwstuttgart/typeinference/unify/model/TypeParams.java @@ -115,6 +115,14 @@ public final class TypeParams implements Iterable{ return typeParams[i]; } + /** + * Returns the parameters of this object. + * PL 2018-03-17 + */ + public UnifyType[] get() { + return typeParams; + } + /** * Sets the the type t as the i-th parameter and returns a new object * that equals this object, except for the i-th type. diff --git a/src/de/dhbwstuttgart/typeinference/unify/model/Unifier.java b/src/de/dhbwstuttgart/typeinference/unify/model/Unifier.java index 061ba588..8f594844 100644 --- a/src/de/dhbwstuttgart/typeinference/unify/model/Unifier.java +++ b/src/de/dhbwstuttgart/typeinference/unify/model/Unifier.java @@ -1,8 +1,10 @@ package de.dhbwstuttgart.typeinference.unify.model; import java.util.HashMap; +import java.util.HashSet; import java.util.Iterator; import java.util.Map.Entry; +import java.util.Set; import java.util.function.Function; /** @@ -63,7 +65,44 @@ public class Unifier implements Function, Iterable suniUnifyPair = new HashSet<>(); + suniUnifyPair.addAll(thisAsPair.getAllSubstitutions()); + suniUnifyPair.add(thisAsPair); + if (p.getLhsType() instanceof PlaceholderType //&& newLhs instanceof PlaceholderType entfernt PL 2018-04-13 + && p.getPairOp() == PairOperator.EQUALSDOT) { + suniUnifyPair.add(p); //p koennte auch subsitution sein + } + return new UnifyPair(newLhs, newRhs, p.getPairOp(), suniUnifyPair, p); + } + return new UnifyPair(newLhs, newRhs, p.getPairOp(), p.getSubstitution(), p.getBasePair()); } /** diff --git a/src/de/dhbwstuttgart/typeinference/unify/model/UnifyPair.java b/src/de/dhbwstuttgart/typeinference/unify/model/UnifyPair.java index 0909690a..19dee99f 100644 --- a/src/de/dhbwstuttgart/typeinference/unify/model/UnifyPair.java +++ b/src/de/dhbwstuttgart/typeinference/unify/model/UnifyPair.java @@ -2,7 +2,10 @@ package de.dhbwstuttgart.typeinference.unify.model; import java.util.ArrayList; import java.util.Collection; +import java.util.HashSet; import java.util.List; +import java.util.Set; + /** * A pair which contains two types and an operator, e.q. (Integer <. a). @@ -25,6 +28,29 @@ public class UnifyPair { */ private PairOperator pairOp; + /** wieder loesecn wird nicht mehr benoetigt PL 2018-03-31 + * variance shows the variance of the pair + * -1: contravariant + * 1 covariant + * 0 invariant + * PL 2018-03-21 + */ + private byte variance = 0; + + private boolean undefinedPair = false; + + /** + * Unifier/substitute that generated this pair + * PL 2018-03-15 + */ + private Set substitution; + + /** + * Base on which the the unifier is applied + * PL 2018-03-15 + */ + private UnifyPair basePair; + private final int hashCode; /** @@ -37,6 +63,20 @@ public class UnifyPair { this.lhs = lhs; this.rhs = rhs; pairOp = op; + substitution = new HashSet<>(); + + // Caching hashcode + hashCode = 17 + 31 * lhs.hashCode() + 31 * rhs.hashCode() + 31 * pairOp.hashCode(); + } + + public UnifyPair(UnifyType lhs, UnifyType rhs, PairOperator op, Set uni, UnifyPair base) { + this.lhs = lhs; + this.rhs = rhs; + pairOp = op; + substitution = uni; + basePair = base; + this.variance = variance; + // Caching hashcode hashCode = 17 + 31 * lhs.hashCode() + 31 * rhs.hashCode() + 31 * pairOp.hashCode(); @@ -63,6 +103,41 @@ public class UnifyPair { return pairOp; } + public byte getVariance() { + return variance; + } + + public void setVariance(byte v) { + variance = v; + } + + public void setUndefinedPair() { + undefinedPair = true; + } + public Set getSubstitution() { + return substitution; + } + + public UnifyPair getBasePair() { + return basePair; + } + public boolean isUndefinedPair() { + return undefinedPair; + } + + public Set getAllSubstitutions () { + Set ret = new HashSet<>(); + ret.addAll(getSubstitution()); + if (basePair != null) { + ret.addAll(basePair.getAllSubstitutions()); + } + return ret; + } + + public Boolean wrongWildcard() { + return lhs.wrongWildcard() || rhs.wrongWildcard(); + } + @Override public boolean equals(Object obj) { if(!(obj instanceof UnifyPair)) @@ -73,6 +148,16 @@ public class UnifyPair { UnifyPair other = (UnifyPair) obj; + if (isUndefinedPair()) { + if (other.getBasePair() != basePair || (other.getBasePair() == null && basePair == null)) { + return false; + } + if (!other.getBasePair().equals(basePair) || + !other.getAllSubstitutions().equals(getAllSubstitutions())) { + return false; + } + } + return other.getPairOp() == pairOp && other.getLhsType().equals(lhs) && other.getRhsType().equals(rhs); @@ -85,7 +170,14 @@ public class UnifyPair { @Override public String toString() { - return "(" + lhs + " " + pairOp + " " + rhs + ")"; + String ret = ""; + if (lhs instanceof PlaceholderType) { + ret = new Integer(((PlaceholderType)lhs).getVariance()).toString(); + } + if (rhs instanceof PlaceholderType) { + ret = ret + ", " + new Integer(((PlaceholderType)rhs).getVariance()).toString(); + } + return "(" + lhs + " " + pairOp + " " + rhs + ", " + ret + ")"; } /* diff --git a/src/de/dhbwstuttgart/typeinference/unify/model/UnifyType.java b/src/de/dhbwstuttgart/typeinference/unify/model/UnifyType.java index 1080f03b..715d9880 100644 --- a/src/de/dhbwstuttgart/typeinference/unify/model/UnifyType.java +++ b/src/de/dhbwstuttgart/typeinference/unify/model/UnifyType.java @@ -2,10 +2,13 @@ package de.dhbwstuttgart.typeinference.unify.model; import java.util.ArrayList; import java.util.Collection; +import java.util.HashMap; import java.util.List; import java.util.Set; +import de.dhbwstuttgart.syntaxtree.StatementVisitor; import de.dhbwstuttgart.typeinference.unify.interfaces.IFiniteClosure; +import de.dhbwstuttgart.typeinference.unify.interfaces.UnifyTypeVisitor; /** * Represents a java type. @@ -33,6 +36,9 @@ public abstract class UnifyType { typeParams = p; } + + abstract public UnifyType accept(UnifyTypeVisitor visitor, T ht); + /** * Returns the name of the type. * @return The name e.q. List for List, Integer or ? extends Integer @@ -96,6 +102,10 @@ public abstract class UnifyType { ret.addAll(typeParams.getInvolvedPlaceholderTypes()); return ret; } + + public Boolean wrongWildcard() {//default + return false; + } @Override public int hashCode() { diff --git a/src/de/dhbwstuttgart/typeinference/unify/model/WildcardType.java b/src/de/dhbwstuttgart/typeinference/unify/model/WildcardType.java index 2bc51460..81999492 100644 --- a/src/de/dhbwstuttgart/typeinference/unify/model/WildcardType.java +++ b/src/de/dhbwstuttgart/typeinference/unify/model/WildcardType.java @@ -40,6 +40,11 @@ public abstract class WildcardType extends UnifyType { return wildcardedType.getTypeParams(); } + @Override + public Boolean wrongWildcard () {//This is an error + return (wildcardedType instanceof WildcardType); + } + @Override public int hashCode() { return wildcardedType.hashCode() + getName().hashCode() + 17; diff --git a/src/de/dhbwstuttgart/typeinference/unify/visitUnifyTypeVisitor.java b/src/de/dhbwstuttgart/typeinference/unify/visitUnifyTypeVisitor.java new file mode 100644 index 00000000..9ea3dc59 --- /dev/null +++ b/src/de/dhbwstuttgart/typeinference/unify/visitUnifyTypeVisitor.java @@ -0,0 +1,47 @@ +package de.dhbwstuttgart.typeinference.unify; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.HashMap; +import java.util.stream.Collectors; + +import de.dhbwstuttgart.typeinference.unify.interfaces.UnifyTypeVisitor; +import de.dhbwstuttgart.typeinference.unify.model.ExtendsType; +import de.dhbwstuttgart.typeinference.unify.model.FunNType; +import de.dhbwstuttgart.typeinference.unify.model.PlaceholderType; +import de.dhbwstuttgart.typeinference.unify.model.ReferenceType; +import de.dhbwstuttgart.typeinference.unify.model.SuperType; +import de.dhbwstuttgart.typeinference.unify.model.TypeParams; + +public class visitUnifyTypeVisitor implements UnifyTypeVisitor { + + public ReferenceType visit(ReferenceType refty, T ht) { + return new ReferenceType(refty.getName(), + new TypeParams( + Arrays.stream(refty.getTypeParams().get()) + .map(x -> x.accept(this, ht)) + .collect(Collectors.toCollection(ArrayList::new)))); + } + + public PlaceholderType visit(PlaceholderType phty, T ht) { + return phty; + } + + public FunNType visit(FunNType funnty, T ht) { + return FunNType.getFunNType( + new TypeParams( + Arrays.stream(funnty.getTypeParams().get()) + .map(x -> x.accept(this, ht)) + .collect(Collectors.toCollection(ArrayList::new))) + ); + } + + public SuperType visit(SuperType suty, T ht) { + return new SuperType(suty.getWildcardedType().accept(this, ht)); + } + + public ExtendsType visit(ExtendsType extty, T ht) { + return new ExtendsType(extty.getWildcardedType().accept(this, ht)); + } +} diff --git a/test/bytecode/BinaryTest.java b/test/bytecode/BinaryTest.java new file mode 100644 index 00000000..7f2f5fa4 --- /dev/null +++ b/test/bytecode/BinaryTest.java @@ -0,0 +1,40 @@ +package bytecode; + +import static org.junit.Assert.*; + +import java.io.File; +import java.net.URL; +import java.net.URLClassLoader; + +import org.junit.BeforeClass; +import org.junit.Test; + +import de.dhbwstuttgart.core.JavaTXCompiler; + +public class BinaryTest { + 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/BinaryInMeth.jav"; + fileToTest = new File(path); + compiler = new JavaTXCompiler(fileToTest); + compiler.generateBytecode(); + pathToClassFile = System.getProperty("user.dir")+"/testBytecode/generatedBC/"; + loader = new URLClassLoader(new URL[] {new URL("file://"+pathToClassFile)}); + classToTest = loader.loadClass("BinaryInMeth"); + instanceOfClass = classToTest.getDeclaredConstructor().newInstance(); + } + + @Test + public void test() { + fail("Not yet implemented"); + } + +} diff --git a/test/bytecode/FacTest.java b/test/bytecode/FacTest.java new file mode 100644 index 00000000..b2840026 --- /dev/null +++ b/test/bytecode/FacTest.java @@ -0,0 +1,44 @@ +package bytecode; + +import static org.junit.Assert.*; + +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.BeforeClass; +import org.junit.Test; + +import de.dhbwstuttgart.core.JavaTXCompiler; + +public class FacTest { + 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/Fac.jav"; + fileToTest = new File(path); + compiler = new JavaTXCompiler(fileToTest); + compiler.generateBytecode(); + pathToClassFile = System.getProperty("user.dir")+"/testBytecode/generatedBC/"; + loader = new URLClassLoader(new URL[] {new URL("file://"+pathToClassFile)}); + classToTest = loader.loadClass("Fac"); + instanceOfClass = classToTest.getDeclaredConstructor().newInstance(); + } + + @Test + public void test() throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { + Method getFac = classToTest.getDeclaredMethod("getFac", Integer.class,Integer.class); + Integer result = (Integer) getFac.invoke(instanceOfClass,3); + assertEquals(result, 6); + } + +} diff --git a/test/bytecode/PlusTest.java b/test/bytecode/PlusTest.java index 016cb706..51503c58 100644 --- a/test/bytecode/PlusTest.java +++ b/test/bytecode/PlusTest.java @@ -29,7 +29,7 @@ public class PlusTest { compiler = new JavaTXCompiler(fileToTest); compiler.generateBytecode(); - pathToClassFile = System.getProperty("user.dir")+"/testBytecode/generatedBC/examples/"; + pathToClassFile = System.getProperty("user.dir")+"/testBytecode/generatedBC/"; loader = new URLClassLoader(new URL[] {new URL("file://"+pathToClassFile)}); classToTest = loader.loadClass("Plus"); instanceOfClass = classToTest.getDeclaredConstructor().newInstance(); diff --git a/test/bytecode/RelOpsTest.java b/test/bytecode/RelOpsTest.java new file mode 100644 index 00000000..06b24630 --- /dev/null +++ b/test/bytecode/RelOpsTest.java @@ -0,0 +1,44 @@ +package bytecode; + +import static org.junit.Assert.*; + +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.BeforeClass; +import org.junit.Test; + +import de.dhbwstuttgart.core.JavaTXCompiler; + +public class RelOpsTest { + 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/RelOps.jav"; + fileToTest = new File(path); + compiler = new JavaTXCompiler(fileToTest); + compiler.generateBytecode(); + pathToClassFile = System.getProperty("user.dir")+"/testBytecode/generatedBC/"; + loader = new URLClassLoader(new URL[] {new URL("file://"+pathToClassFile)}); + classToTest = loader.loadClass("RelOps"); + instanceOfClass = classToTest.getDeclaredConstructor().newInstance(); + } + + @Test + public void test() throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { + Method m = classToTest.getDeclaredMethod("m", Integer.class,Integer.class); + Boolean result = (Boolean) m.invoke(instanceOfClass, 7,3); + assertFalse(result); + } + +} diff --git a/test/bytecode/javFiles/BinaryInMeth.jav b/test/bytecode/javFiles/BinaryInMeth.jav new file mode 100644 index 00000000..f5a11798 --- /dev/null +++ b/test/bytecode/javFiles/BinaryInMeth.jav @@ -0,0 +1,11 @@ +import java.lang.Integer; +public class BinaryInMeth { + + m(a){ + return ++a; + } + + m2(a,b){ + return m(a+b); + } +} \ No newline at end of file diff --git a/test/bytecode/javFiles/Fac.jav b/test/bytecode/javFiles/Fac.jav new file mode 100644 index 00000000..d3d1a8d9 --- /dev/null +++ b/test/bytecode/javFiles/Fac.jav @@ -0,0 +1,16 @@ +import java.lang.Integer; +import java.lang.Long; +import java.lang.Double; + +public class Fac { + + getFac(n){ + var res = 1; + var i = 1; + while(i<=n) { + res = res * i; + i++; + } + return res; + } +} \ No newline at end of file diff --git a/test/bytecode/javFiles/Gen.jav b/test/bytecode/javFiles/Gen.jav index 5d579eb8..3b58b188 100644 --- a/test/bytecode/javFiles/Gen.jav +++ b/test/bytecode/javFiles/Gen.jav @@ -2,7 +2,7 @@ import java.lang.Integer; import java.util.Vector; public class Gen{ - Vector m(Vector v){ + Vector m(Vector v){ return v; } } diff --git a/test/bytecode/javFiles/Matrix.jav b/test/bytecode/javFiles/Matrix.jav index 8120a7c5..80f41b16 100644 --- a/test/bytecode/javFiles/Matrix.jav +++ b/test/bytecode/javFiles/Matrix.jav @@ -7,19 +7,19 @@ class Matrix extends Vector> { var ret = new Matrix(); var i = 0; while(i < size()) { - var v1 = this.elementAt(i); - var v2 = new Vector(); - var j = 0; - while(j < v1.size()) { - var erg = 0; - var k = 0; - while(k < v1.size()) { - erg = erg + v1.elementAt(k) - * m.elementAt(k).elementAt(j); - k++; } - v2.addElement(new Integer(erg)); - j++; } - ret.addElement(v2); +// var v1 = this.elementAt(i); +// var v2 = new Vector(); +// var j = 0; +// while(j < v1.size()) { +// var erg = 0; +// var k = 0; +// while(k < v1.size()) { +// erg = erg + v1.elementAt(k) +// * m.elementAt(k).elementAt(j); +// k++; } +// v2.addElement(new Integer(erg)); +// j++; } +// ret.addElement(v2); i++; } return ret; diff --git a/test/bytecode/javFiles/Op.jav b/test/bytecode/javFiles/Op.jav index c01e7e6e..082f48d8 100644 --- a/test/bytecode/javFiles/Op.jav +++ b/test/bytecode/javFiles/Op.jav @@ -9,7 +9,7 @@ import java.lang.Byte; public class Op { - Integer m(Integer a, Integer b) { + m(a, b) { //var c = a+b; return a+b; } diff --git a/test/bytecode/javFiles/Plus.jav b/test/bytecode/javFiles/Plus.jav index 4d425bf0..86b4eb36 100644 --- a/test/bytecode/javFiles/Plus.jav +++ b/test/bytecode/javFiles/Plus.jav @@ -1,4 +1,4 @@ -import java.lang.Integer; +//import java.lang.Integer; public class Plus { diff --git a/test/bytecode/javFiles/RelOps.jav b/test/bytecode/javFiles/RelOps.jav new file mode 100644 index 00000000..d75ee2f3 --- /dev/null +++ b/test/bytecode/javFiles/RelOps.jav @@ -0,0 +1,7 @@ +import java.lang.Integer; + +public class RelOps { + m(a,b){ + return a Deswegen kann +// nicht auf den Stack geladen. +import java.lang.Long; public class While { m(x) { diff --git a/test/finiteClosure/SuperInterfacesTest.java b/test/finiteClosure/SuperInterfacesTest.java new file mode 100644 index 00000000..f00bf068 --- /dev/null +++ b/test/finiteClosure/SuperInterfacesTest.java @@ -0,0 +1,31 @@ +package finiteClosure; + +import de.dhbwstuttgart.parser.SyntaxTreeGenerator.FCGenerator; +import de.dhbwstuttgart.syntaxtree.ClassOrInterface; +import de.dhbwstuttgart.syntaxtree.factory.ASTFactory; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +public class SuperInterfacesTest { + @Test + public void test() throws ClassNotFoundException { + Collection classes = new ArrayList<>(); + classes.add(ASTFactory.createClass(TestClass.class)); + System.out.println(FCGenerator.toFC(classes)); + } +} + +class TestClass implements Test2, Test3{ + +} + +interface Test2 { + +} + +interface Test3{ + +} \ No newline at end of file diff --git a/test/javFiles/FC_Matrix.jav b/test/javFiles/FC_Matrix.jav new file mode 100644 index 00000000..75ead472 --- /dev/null +++ b/test/javFiles/FC_Matrix.jav @@ -0,0 +1,10 @@ +import java.util.Vector; + +class Matrix extends Vector> { + + methode(m) { + m.add(1); + Matrix i; + methode(i); + } + } diff --git a/test/javFiles/Lambda.jav b/test/javFiles/Lambda.jav index 378eb4d3..553dc496 100644 --- a/test/javFiles/Lambda.jav +++ b/test/javFiles/Lambda.jav @@ -1,18 +1,13 @@ -class Lambda{ +import java.lang.Integer; +import java.lang.Number; -methode(){ - return ((f) -> f); -} -} -/* -interface Fun0{ - A apply(); +public class Lambda { + + m () { + var lam1 = (x) -> { + return x; + }; + return lam1; + } } -interface Fun1{ - A apply(B b); -} -*/ -interface Fun2{ - A apply(B b, C c); -} \ No newline at end of file diff --git a/test/javFiles/Lambda2.jav b/test/javFiles/Lambda2.jav index fbcdaf55..cf1e910b 100644 --- a/test/javFiles/Lambda2.jav +++ b/test/javFiles/Lambda2.jav @@ -1,3 +1,4 @@ +import java.lang.String; public class Lambda2 { diff --git a/test/javFiles/Lambda3.jav b/test/javFiles/Lambda3.jav index 9c4e960c..9e22f302 100644 --- a/test/javFiles/Lambda3.jav +++ b/test/javFiles/Lambda3.jav @@ -1,3 +1,4 @@ +import java.lang.String; public class Lambda2 { diff --git a/test/javFiles/LambdaField.jav b/test/javFiles/LambdaField.jav new file mode 100644 index 00000000..4eb53738 --- /dev/null +++ b/test/javFiles/LambdaField.jav @@ -0,0 +1,6 @@ +public class LambdaField { + + f = x -> x; + +} + diff --git a/test/javFiles/Matrix.jav b/test/javFiles/Matrix.jav index aa8966c9..8b01c235 100644 --- a/test/javFiles/Matrix.jav +++ b/test/javFiles/Matrix.jav @@ -1,26 +1,28 @@ import java.util.Vector; import java.lang.Integer; -import java.lang.Boolean; class Matrix extends Vector> { + Integer mul1(Integer x, Integer y) { return x;} + Integer add1(Integer x, Integer y) { return x;} mul(m) { var ret = new Matrix(); var i = 0; - //while(i < size()) { + while(i < size()) { var v1 = this.elementAt(i); - //var v2 = new Vector(); - //var j = 0; - //while(j < v1.size()) { - //var erg = 0; - //var k = 0; - //while(k < v1.size()) { - //erg = erg + v1.elementAt(k) - // * m.elementAt(k).elementAt(j); - //k++; } - //v2.addElement(new Integer(erg)); - //j++; } - //ret.addElement(v2); - //i++; } + var v2 = new Vector(); + var j = 0; + while(j < v1.size()) { + var erg = 0; + var k = 0; + while(k < v1.size()) { + erg = erg + v1.elementAt(k) * m.elementAt(k).elementAt(j); + //erg = add1(erg, mul1(v1.elementAt(k), + // m.elementAt(k).elementAt(j))); + k++; } + v2.addElement(new Integer(erg)); + j++; } + ret.addElement(v2); + i++; } return ret; } } diff --git a/test/javFiles/Meth_Gen.jav b/test/javFiles/Meth_Gen.jav new file mode 100644 index 00000000..056dd82f --- /dev/null +++ b/test/javFiles/Meth_Gen.jav @@ -0,0 +1,11 @@ +class Meth_Gen { + + m1(x, y) { + m2(x); + x = y; + } + + m2(y) { + m1(y, y); + } +} \ No newline at end of file diff --git a/test/typeinference/JavaTXCompilerTest.java b/test/typeinference/JavaTXCompilerTest.java index 3ba22bc6..cf0f31db 100644 --- a/test/typeinference/JavaTXCompilerTest.java +++ b/test/typeinference/JavaTXCompilerTest.java @@ -99,7 +99,11 @@ public class JavaTXCompilerTest { // //filesToTest.add(new File(rootDirectory+"mathStruc.jav")); // //filesToTest.add(new File(rootDirectory+"test.jav")); JavaTXCompiler compiler = new JavaTXCompiler(fileToTest); - + for(File f : compiler.sourceFiles.keySet()){ + SourceFile sf = compiler.sourceFiles.get(f); + System.out.println(ASTTypePrinter.print(sf)); + System.out.println(ASTPrinter.print(sf)); + } List results = compiler.typeInference(); for(File f : compiler.sourceFiles.keySet()){ diff --git a/test/typeinference/Meth_GenTest.java b/test/typeinference/Meth_GenTest.java new file mode 100644 index 00000000..f5e64f9f --- /dev/null +++ b/test/typeinference/Meth_GenTest.java @@ -0,0 +1,139 @@ +package typeinference; + +import de.dhbwstuttgart.core.JavaTXCompiler; +import de.dhbwstuttgart.syntaxtree.SourceFile; +import de.dhbwstuttgart.syntaxtree.visual.ASTPrinter; +import de.dhbwstuttgart.syntaxtree.visual.ASTTypePrinter; +import de.dhbwstuttgart.typedeployment.TypeInsert; +import de.dhbwstuttgart.typedeployment.TypeInsertFactory; +import de.dhbwstuttgart.typeinference.result.ResultSet; +import org.junit.Test; + +import java.io.File; +import java.io.IOException; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +public class Meth_GenTest { + + public static final String rootDirectory = System.getProperty("user.dir")+"/test/javFiles/"; +/* + @Test + public void finiteClosure() throws IOException, ClassNotFoundException { + execute(new File(rootDirectory+"fc.jav")); + } + @Test + public void lambda() throws IOException, ClassNotFoundException { + execute(new File(rootDirectory+"Lambda.jav")); + } + @Test + public void lambda2() throws IOException, ClassNotFoundException { + execute(new File(rootDirectory+"Lambda2.jav")); + } + @Test + public void lambda3() throws IOException, ClassNotFoundException { + execute(new File(rootDirectory+"Lambda3.jav")); + } + @Test + public void mathStruc() throws IOException, ClassNotFoundException { + execute(new File(rootDirectory+"mathStruc.jav")); + } + @Test + public void generics() throws IOException, ClassNotFoundException { + execute(new File(rootDirectory+"Generics.jav")); + } + + @Test + public void faculty() throws IOException, ClassNotFoundException { + execute(new File(rootDirectory+"Faculty.jav")); + } + + @Test + public void facultyTyped() throws IOException, ClassNotFoundException { + execute(new File(rootDirectory+"FacultyTyped.jav")); + } +*/ + @Test + public void matrix() throws IOException, ClassNotFoundException { + execute(new File(rootDirectory+"Meth_Gen.jav")); + } +/* + @Test + public void vector() throws IOException, ClassNotFoundException { + execute(new File(rootDirectory+"Vector.jav")); + } + @Test + public void lambdaRunnable() throws IOException, ClassNotFoundException { + execute(new File(rootDirectory+"LambdaRunnable.jav")); + } + @Test + public void expressions() throws IOException, ClassNotFoundException { + execute(new File(rootDirectory+"Expressions.jav")); + } + @Test + public void matrixFC() throws IOException, ClassNotFoundException { + execute(new File(rootDirectory+"FC_Matrix.jav")); + } +*/ + private static class TestResultSet{ + + } + + public TestResultSet execute(File fileToTest) throws IOException, ClassNotFoundException { + //filesToTest.add(new File(rootDirectory+"fc.jav")); + //filesToTest.add(new File(rootDirectory+"Lambda.jav")); + //filesToTest.add(new File(rootDirectory+"Lambda2.jav")); + //filesToTest.add(new File(rootDirectory+"Lambda3.jav")); + //filesToTest.add(new File(rootDirectory+"Vector.jav")); + //filesToTest.add(new File(rootDirectory+"Generics.jav")); + //filesToTest.add(new File(rootDirectory+"MethodsEasy.jav")); + //filesToTest.add(new File(rootDirectory+"Matrix.jav")); + //filesToTest.add(new File(rootDirectory+"Import.jav")); + // //filesToTest.add(new File(rootDirectory+"Faculty.jav")); + // //filesToTest.add(new File(rootDirectory+"mathStruc.jav")); + // //filesToTest.add(new File(rootDirectory+"test.jav")); + JavaTXCompiler compiler = new JavaTXCompiler(fileToTest); + for(File f : compiler.sourceFiles.keySet()){ + SourceFile sf = compiler.sourceFiles.get(f); + System.out.println(ASTTypePrinter.print(sf)); + System.out.println(ASTPrinter.print(sf)); + } + List results = compiler.typeInference(); + + for(File f : compiler.sourceFiles.keySet()){ + SourceFile sf = compiler.sourceFiles.get(f); + System.out.println(ASTTypePrinter.print(sf)); + System.out.println(ASTPrinter.print(sf)); + //List results = compiler.typeInference(); PL 2017-10-03 vor die For-Schleife gezogen + assert results.size()>0; + Set insertedTypes = new HashSet<>(); + for(ResultSet resultSet : results){ + Set result = TypeInsertFactory.createTypeInsertPoints(sf, resultSet); + assert result.size()>0; + String content = readFile(f.getPath(), StandardCharsets.UTF_8); + for(TypeInsert tip : result){ + insertedTypes.add(tip.insert(content)); + } + } + for(String s : insertedTypes){ + System.out.println(s); + } + } + return new TestResultSet(); + } + + static String readFile(String path, Charset encoding) + throws IOException + { + byte[] encoded = Files.readAllBytes(Paths.get(path)); + return new String(encoded, encoding); + } + +} + diff --git a/test/typeinference/UnifyTest.java b/test/typeinference/UnifyTest.java new file mode 100644 index 00000000..2a496166 --- /dev/null +++ b/test/typeinference/UnifyTest.java @@ -0,0 +1,158 @@ +package typeinference; + +import de.dhbwstuttgart.core.JavaTXCompiler; +import de.dhbwstuttgart.syntaxtree.SourceFile; +import de.dhbwstuttgart.syntaxtree.visual.ASTPrinter; +import de.dhbwstuttgart.syntaxtree.visual.ASTTypePrinter; +import de.dhbwstuttgart.typedeployment.TypeInsert; +import de.dhbwstuttgart.typedeployment.TypeInsertFactory; +import de.dhbwstuttgart.typeinference.result.ResultSet; +import org.junit.Test; + +import java.io.File; +import java.io.IOException; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +public class UnifyTest { + + public static final String rootDirectory = System.getProperty("user.dir")+"/test/javFiles/"; +/* + @Test + public void finiteClosure() throws IOException, ClassNotFoundException { + execute(new File(rootDirectory+"fc.jav")); + } + */ +/* + @Test + public void lambda() throws IOException, ClassNotFoundException { + execute(new File(rootDirectory+"Lambda.jav")); + } +*/ + /* + @Test + public void lambda2() throws IOException, ClassNotFoundException { + execute(new File(rootDirectory+"Lambda2.jav")); + } + */ +/* + @Test + public void lambda3() throws IOException, ClassNotFoundException { + execute(new File(rootDirectory+"Lambda3.jav")); + } + + @Test + public void lambdafield() throws IOException, ClassNotFoundException { + execute(new File(rootDirectory+"LambdaField.jav")); + } + + @Test + public void mathStruc() throws IOException, ClassNotFoundException { + execute(new File(rootDirectory+"mathStruc.jav")); + } + @Test + public void generics() throws IOException, ClassNotFoundException { + execute(new File(rootDirectory+"Generics.jav")); + } +*/ +/* + @Test + public void faculty() throws IOException, ClassNotFoundException { + execute(new File(rootDirectory+"Faculty.jav")); + } +*/ +/* + @Test + public void facultyTyped() throws IOException, ClassNotFoundException { + execute(new File(rootDirectory+"FacultyTyped.jav")); + } + */ + + + @Test + public void matrix() throws IOException, ClassNotFoundException { + execute(new File(rootDirectory+"Matrix.jav")); + //JavaTXCompiler compiler = new JavaTXCompiler(new File(rootDirectory+"Matrix.jav")); + //compiler.generateBytecode(); + } + +/* + @Test + public void vector() throws IOException, ClassNotFoundException { + execute(new File(rootDirectory+"Vector.jav")); + } + @Test + public void lambdaRunnable() throws IOException, ClassNotFoundException { + execute(new File(rootDirectory+"LambdaRunnable.jav")); + } + @Test + public void expressions() throws IOException, ClassNotFoundException { + execute(new File(rootDirectory+"Expressions.jav")); + } + @Test + public void matrixFC() throws IOException, ClassNotFoundException { + execute(new File(rootDirectory+"FC_Matrix.jav")); + } +*/ + private static class TestResultSet{ + + } + + public TestResultSet execute(File fileToTest) throws IOException, ClassNotFoundException { + //filesToTest.add(new File(rootDirectory+"fc.jav")); + //filesToTest.add(new File(rootDirectory+"Lambda.jav")); + //filesToTest.add(new File(rootDirectory+"Lambda2.jav")); + //filesToTest.add(new File(rootDirectory+"Lambda3.jav")); + //filesToTest.add(new File(rootDirectory+"Vector.jav")); + //filesToTest.add(new File(rootDirectory+"Generics.jav")); + //filesToTest.add(new File(rootDirectory+"MethodsEasy.jav")); + //filesToTest.add(new File(rootDirectory+"Matrix.jav")); + //filesToTest.add(new File(rootDirectory+"Import.jav")); + // //filesToTest.add(new File(rootDirectory+"Faculty.jav")); + // //filesToTest.add(new File(rootDirectory+"mathStruc.jav")); + // //filesToTest.add(new File(rootDirectory+"test.jav")); + JavaTXCompiler compiler = new JavaTXCompiler(fileToTest); + for(File f : compiler.sourceFiles.keySet()){ + SourceFile sf = compiler.sourceFiles.get(f); + System.out.println(ASTTypePrinter.print(sf)); + System.out.println(ASTPrinter.print(sf)); + } + List results = compiler.typeInference(); + + for(File f : compiler.sourceFiles.keySet()){ + SourceFile sf = compiler.sourceFiles.get(f); + System.out.println(ASTTypePrinter.print(sf)); + System.out.println(ASTPrinter.print(sf)); + //List results = compiler.typeInference(); PL 2017-10-03 vor die For-Schleife gezogen + assert results.size()>0; + Set insertedTypes = new HashSet<>(); + for(ResultSet resultSet : results){ + Set result = TypeInsertFactory.createTypeInsertPoints(sf, resultSet); + assert result.size()>0; + String content = readFile(f.getPath(), StandardCharsets.UTF_8); + for(TypeInsert tip : result){ + insertedTypes.add(tip.insert(content)); + } + } + for(String s : insertedTypes){ + System.out.println(s); + } + } + return new TestResultSet(); + } + + static String readFile(String path, Charset encoding) + throws IOException + { + byte[] encoded = Files.readAllBytes(Paths.get(path)); + return new String(encoded, encoding); + } + +} +