diff --git a/AlgebraicDataflowArchitectureModel/src/algorithms/TypeInference.java b/AlgebraicDataflowArchitectureModel/src/algorithms/TypeInference.java index 3eaffde..7b6de77 100644 --- a/AlgebraicDataflowArchitectureModel/src/algorithms/TypeInference.java +++ b/AlgebraicDataflowArchitectureModel/src/algorithms/TypeInference.java @@ -2,6 +2,7 @@ import java.util.AbstractMap; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; @@ -79,7 +80,7 @@ listComponentTypes.put(DataConstraintModel.typeListStr, DataConstraintModel.typeString); listTypes.put(DataConstraintModel.typeInt, DataConstraintModel.typeListInt); listTypes.put(DataConstraintModel.typeString, DataConstraintModel.typeListStr); - tupleComponentTypes.put(DataConstraintModel.typeTuple, null); + tupleComponentTypes.put(DataConstraintModel.typeTuple, Arrays.asList(new Type[] {null, null})); for (Node n: graph.getNodes()) { ResourceNode resource = (ResourceNode) n; idToRes.put(resource.getIdentifierTemplate(), resource); @@ -382,6 +383,82 @@ updateExps.put(System.identityHashCode(t), t); } tuple.put(System.identityHashCode(tupleExps), t.getType()); + } else if (symbol.equals(DataConstraintModel.fst)) { + // If the root symbol of the term is fst. + List tupleExps = new ArrayList<>(); + Expression arg = t.getChildren().get(0); + tupleExps.add(arg); + expToTuple.put(System.identityHashCode(arg), tupleExps); + tupleExps.add(t); + expToTuple.put(System.identityHashCode(t), tupleExps); + tupleExps.add(null); + Type argType = null; + if (arg instanceof Variable) { + argType = ((Variable) arg).getType(); + } else if (arg instanceof Term) { + argType = ((Term) arg).getType(); + } + Type newTupleType = DataConstraintModel.typeTuple; + if (argType == DataConstraintModel.typeTuple && t.getType() != null) { + List compTypeList = new ArrayList<>(); + compTypeList.add(t.getType()); + compTypeList.add(null); + newTupleType = tupleTypes.get(compTypeList); + if (newTupleType == null) { + // Create new tuple type; + newTupleType = createNewTupleType(compTypeList, DataConstraintModel.typeTuple); + } + } + if (argType != newTupleType && newTupleType != null) { + if (arg instanceof Variable) { + ((Variable) arg).setType(newTupleType); + argType = newTupleType; + } else if (arg instanceof Term) { + ((Term) arg).setType(newTupleType); + argType = newTupleType; + } + Map updateExps = getUpdateSet(updateFromTuple, tupleExps); + updateExps.put(System.identityHashCode(arg), arg); + } + tuple.put(System.identityHashCode(tupleExps), argType); + } else if (symbol.equals(DataConstraintModel.snd)) { + // If the root symbol of the term is snd. + List tupleExps = new ArrayList<>(); + Expression arg = t.getChildren().get(0); + tupleExps.add(arg); + expToTuple.put(System.identityHashCode(arg), tupleExps); + tupleExps.add(null); + tupleExps.add(t); + expToTuple.put(System.identityHashCode(t), tupleExps); + Type argType = null; + if (arg instanceof Variable) { + argType = ((Variable) arg).getType(); + } else if (arg instanceof Term) { + argType = ((Term) arg).getType(); + } + Type newTupleType = DataConstraintModel.typeTuple; + if (argType == DataConstraintModel.typeTuple && t.getType() != null) { + List compTypeList = new ArrayList<>(); + compTypeList.add(null); + compTypeList.add(t.getType()); + newTupleType = tupleTypes.get(compTypeList); + if (newTupleType == null) { + // Create new tuple type; + newTupleType = createNewTupleType(compTypeList, DataConstraintModel.typeTuple); + } + } + if (argType != newTupleType && newTupleType != null) { + if (arg instanceof Variable) { + ((Variable) arg).setType(newTupleType); + argType = newTupleType; + } else if (arg instanceof Term) { + ((Term) arg).setType(newTupleType); + argType = newTupleType; + } + Map updateExps = getUpdateSet(updateFromTuple, tupleExps); + updateExps.put(System.identityHashCode(arg), arg); + } + tuple.put(System.identityHashCode(tupleExps), argType); } else if (symbol.equals(DataConstraintModel.cond)) { // If the root symbol of the term is if function. Expression c1 = t.getChild(1); @@ -431,6 +508,56 @@ } } variables.put(System.identityHashCode(condTerms), condType); + } else if (symbol.equals(DataConstraintModel.add) || symbol.equals(DataConstraintModel.sub) + || symbol.equals(DataConstraintModel.mul) || symbol.equals(DataConstraintModel.div)) { + // If the root symbol of the term is arithmetic operators. + Expression c1 = t.getChild(0); + Expression c2 = t.getChild(1); + List operands = new ArrayList<>(); + operands.add(t); + operands.add(c1); + operands.add(c2); + expToVariable.put(System.identityHashCode(t), operands); + expToVariable.put(System.identityHashCode(c1), operands); + expToVariable.put(System.identityHashCode(c2), operands); + Type opType = t.getType(); + Map updatedVars = getUpdateSet(updateFromVariable, operands); + Type child1Type = getExpTypeIfUpdatable(opType, c1); + if (child1Type != null) { + opType = child1Type; + t.setType(child1Type); + updatedVars.put(System.identityHashCode(t), t); + } else { + if (c1 instanceof Variable && compareTypes(((Variable) c1).getType(), opType)) { + ((Variable) c1).setType(opType); + updatedVars.put(System.identityHashCode(c1), c1); + } else if (c1 instanceof Term && compareTypes(((Term) c1).getType(), opType)) { + ((Term) c1).setType(opType); + updatedVars.put(System.identityHashCode(c1), c1); + } + } + Type child2Type = getExpTypeIfUpdatable(opType, c2); + if (child2Type != null) { + opType = child2Type; + t.setType(child2Type); + updatedVars.put(System.identityHashCode(t), t); + if (c1 instanceof Variable) { + ((Variable) c1).setType(child2Type); + updatedVars.put(System.identityHashCode(c1), c1); + } else if (c1 instanceof Term) { + ((Term) c1).setType(child2Type); + updatedVars.put(System.identityHashCode(c1), c1); + } + } else { + if (c2 instanceof Variable && compareTypes(((Variable) c2).getType(), opType)) { + ((Variable) c2).setType(opType); + updatedVars.put(System.identityHashCode(c2), c2); + } else if (c2 instanceof Term && compareTypes(((Term) c2).getType(), opType)) { + ((Term) c2).setType(opType); + updatedVars.put(System.identityHashCode(c2), c2); + } + } + variables.put(System.identityHashCode(operands), opType); } else if (symbol.getSignature() != null && symbol.getSignature()[0] == DataConstraintModel.typeList) { // If the root symbol of the term is the list type (except for the cons function). List consExps = new ArrayList<>(); @@ -706,11 +833,33 @@ private static Type createNewListType(Type compType, Type parentType) { String compTypeName = getInterfaceTypeName(compType); + List childrenTypes = getChildrenTypesOfList(parentType); Type newListType = new Type("List", "ArrayList<>", "List<" + compTypeName + ">", parentType); listTypes.put(compType, newListType); listComponentTypes.put(newListType, compType); + for (Type childType: childrenTypes) { + if (compareTypes(childType, newListType)) { + if (newListType.getParentTypes().contains(parentType)) { + newListType.replaceParentType(parentType, childType); + } else { + newListType.addParentType(childType); + } + } else if (compareTypes(newListType, childType)) { + childType.replaceParentType(parentType, newListType); + } + } return newListType; } + + private static List getChildrenTypesOfList(Type parentListType) { + List childrenTypes = new ArrayList<>(); + for (Type listType: listComponentTypes.keySet()) { + if (listType.getParentTypes().contains(parentListType)) { + childrenTypes.add(listType); + } + } + return childrenTypes; + } private static void updateTupleTypes(Expression exp, Map tuple, Map> expToTuple, Map> updateFromTuple) { List components = expToTuple.get(System.identityHashCode(exp)); @@ -720,19 +869,20 @@ Type tupleType = tuple.get(System.identityHashCode(components)); Type newTupleType = getExpTypeIfUpdatable(tupleType, exp); if (newTupleType != null) { + // Propagate an update of a tuple's type to its components' types. tuple.put(System.identityHashCode(components), newTupleType); List componentTypes = tupleComponentTypes.get(newTupleType); Map updateExps = getUpdateSet(updateFromTuple, components); - for (int i = 0; i < components.size(); i++) { + for (int i = 1; i < components.size(); i++) { Expression compExp = components.get(i); if (compExp instanceof Variable) { - if (compareTypes(((Variable) compExp).getType(), componentTypes.get(i))) { - ((Variable) compExp).setType(componentTypes.get(i)); + if (compareTypes(((Variable) compExp).getType(), componentTypes.get(i - 1))) { + ((Variable) compExp).setType(componentTypes.get(i - 1)); updateExps.put(System.identityHashCode(compExp), compExp); } - }else if (compExp instanceof Term) { - if (compareTypes(((Term) compExp).getType(), componentTypes.get(i))) { - ((Variable) compExp).setType(componentTypes.get(i)); + } else if (compExp instanceof Term) { + if (compareTypes(((Term) compExp).getType(), componentTypes.get(i - 1))) { + ((Term) compExp).setType(componentTypes.get(i - 1)); updateExps.put(System.identityHashCode(compExp), compExp); } } @@ -744,6 +894,7 @@ Type compType = componentTypes.get(idx - 1); Type newCompType = getExpTypeIfUpdatable(compType, exp); if (newCompType != null) { + // Propagate an update of a component's type to its container's (tuple's) type. componentTypes = new ArrayList<>(componentTypes); componentTypes.set(idx - 1, newCompType); Type newTupleType = tupleTypes.get(componentTypes); @@ -751,10 +902,15 @@ // Create new tuple type; newTupleType = createNewTupleType(componentTypes, tupleType); } - Term t = (Term) components.get(0); - t.setType(newTupleType); Map updateExps = getUpdateSet(updateFromTuple, components); - updateExps.put(System.identityHashCode(t), t); + Expression tupleExp = components.get(0); + if (tupleExp instanceof Variable) { + ((Variable) tupleExp).setType(newTupleType); + updateExps.put(System.identityHashCode(tupleExp), tupleExp); + } else if (tupleExp instanceof Term) { + ((Term) tupleExp).setType(newTupleType); + updateExps.put(System.identityHashCode(tupleExp), tupleExp); + } tuple.put(System.identityHashCode(components), newTupleType); } } @@ -773,12 +929,34 @@ implTypeName = implTypeName.replace("$x", ", " + getImplementationTypeName(componentTypes.get(componentTypes.size() - 1))); interfaceTypeName = interfaceTypeName.replace("$x", ", " + getInterfaceTypeName(componentTypes.get(componentTypes.size() - 1))); } + List childrenTypes = getChildrenTypesOfTuple(parentTupleType); Type newTupleType = new Type("Tuple", implTypeName, interfaceTypeName, parentTupleType); tupleTypes.put(componentTypes, newTupleType); tupleComponentTypes.put(newTupleType, componentTypes); + for (Type childType: childrenTypes) { + if (compareTypes(childType, newTupleType)) { + if (newTupleType.getParentTypes().contains(parentTupleType)) { + newTupleType.replaceParentType(parentTupleType, childType); + } else { + newTupleType.addParentType(childType); + } + } else if (compareTypes(newTupleType, childType)) { + childType.replaceParentType(parentTupleType, newTupleType); + } + } return newTupleType; } + private static List getChildrenTypesOfTuple(Type parentTupleType) { + List childrenTypes = new ArrayList<>(); + for (Type tupleType: tupleComponentTypes.keySet()) { + if (tupleType.getParentTypes().contains(parentTupleType)) { + childrenTypes.add(tupleType); + } + } + return childrenTypes; + } + private static String getImplementationTypeName(Type type) { if (type == null) return "Integer"; String wrapperType = DataConstraintModel.getWrapperType(type); @@ -815,9 +993,31 @@ return null; } + /** + * Is an given original type an ancestor of a given new type? + * @param originalType original type + * @param newType new type (may not have been registered) + * @return true: if the original type equals to the new type or is an ancestor of the new type, false: otherwise + */ private static boolean compareTypes(Type originalType, Type newType) { - if (originalType == null || (originalType != newType && newType != null && originalType.isAncestorOf(newType))) { - return true; + if (originalType == null) return true; + if (originalType != newType && newType != null) { + if (originalType.isAncestorOf(newType)) return true; + if (DataConstraintModel.typeTuple.isAncestorOf(originalType) && DataConstraintModel.typeTuple.isAncestorOf(newType)) { + List originalCompTypes = tupleComponentTypes.get(originalType); + List newCompTypes = tupleComponentTypes.get(newType); + if (originalCompTypes == null) return true; + for (int i = 0; i < originalCompTypes.size(); i++) { + if (originalCompTypes.get(i) != null && (newCompTypes.get(i) == null || !originalCompTypes.get(i).isAncestorOf(newCompTypes.get(i)))) return false; + } + return true; + } + if (DataConstraintModel.typeList.isAncestorOf(originalType) && DataConstraintModel.typeList.isAncestorOf(newType)) { + Type originalCompType = listComponentTypes.get(originalType); + Type newCompType = listComponentTypes.get(newType); + if (originalCompType != null && (newCompType == null || !originalCompType.isAncestorOf(newCompType))) return false; + return true; + } } return false; }