diff --git a/AlgebraicDataflowArchitectureModel/src/algorithms/TypeInference.java b/AlgebraicDataflowArchitectureModel/src/algorithms/TypeInference.java index 9f626af..c831849 100644 --- a/AlgebraicDataflowArchitectureModel/src/algorithms/TypeInference.java +++ b/AlgebraicDataflowArchitectureModel/src/algorithms/TypeInference.java @@ -1,105 +1,715 @@ package algorithms; +import java.util.AbstractMap; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + import models.Edge; import models.Node; import models.algebra.Expression; +import models.algebra.Position; import models.algebra.Term; import models.algebra.Type; import models.algebra.Variable; import models.dataConstraintModel.ChannelGenerator; import models.dataConstraintModel.ChannelMember; import models.dataConstraintModel.DataConstraintModel; +import models.dataConstraintModel.IdentifierTemplate; +import models.dataConstraintModel.StateTransition; import models.dataFlowModel.DataFlowModel; -import models.dataFlowModel.DataflowChannelGenerator; -import models.dataFlowModel.PushPullAttribute; -import models.dataFlowModel.PushPullValue; -import models.dataFlowModel.ResourceDependency; import models.dataFlowModel.ResourceDependencyGraph; import models.dataFlowModel.ResourceNode; public class TypeInference { + static private Map listTypes = new HashMap<>(); + static private Map listComponentTypes = new HashMap<>(); + static private Map, Type> tupleTypes = new HashMap<>(); + static private Map> tupleComponentTypes = new HashMap<>(); + static public void infer(ResourceDependencyGraph graph, DataFlowModel model) { + Map> resources = new HashMap<>(); + Map variables = new HashMap<>(); + Map, Type>>> messages = new HashMap<>(); + Map cons = new HashMap<>(); + Map tuple = new HashMap<>(); + Map> expToResource = new HashMap<>(); + Map> expToVariable = new HashMap<>(); + Map> expToMessage = new HashMap<>(); + Map> expToCons = new HashMap<>(); + Map> expToTuple = new HashMap<>(); + + Map idToRes = new HashMap<>(); + Map> updateFromResource = new HashMap<>(); + Map> updateFromVariable = new HashMap<>(); + Map> updateFromMessage = new HashMap<>(); + Map> updateFromCons = new HashMap<>(); + Map> updateFromTuple = new HashMap<>(); + + listComponentTypes.put(DataConstraintModel.typeList, null); + tupleComponentTypes.put(DataConstraintModel.typeTuple, null); for (Node n: graph.getNodes()) { ResourceNode resource = (ResourceNode) n; - Type resourceType = resource.getIdentifierTemplate().getResourceStateType(); - if (resourceType == null || resourceType == DataConstraintModel.typeList) { - if (resource.getIndegree() == 0) { - for (ChannelGenerator c: model.getIOChannelGenerators()) { - for (ChannelMember cm: ((DataflowChannelGenerator) c).getOutputChannelMembers()) { - if (resource.getIdentifierTemplate().equals(cm.getIdentifierTemplate()) - && cm.getStateTransition().getNextStateExpression() instanceof Term) { - updateResourceType(resource, cm); + idToRes.put(resource.getIdentifierTemplate(), resource); + } + + // Collect type information from the architecture model. + Collection channels = new HashSet<>(model.getIOChannelGenerators()); + channels.addAll(model.getChannelGenerators()); + for (ChannelGenerator c: channels) { + for (ChannelMember cm: c.getChannelMembers()) { + StateTransition st = cm.getStateTransition(); + IdentifierTemplate id = cm.getIdentifierTemplate(); + + // Group expressions by resources. + List sameResource = resources.get(id); + if (sameResource == null) { + sameResource = new ArrayList<>(); + resources.put(id, sameResource); + } + sameResource.add(st.getCurStateExpression()); + sameResource.add(st.getNextStateExpression()); + expToResource.put(System.identityHashCode(st.getCurStateExpression()), sameResource); + expToResource.put(System.identityHashCode(st.getNextStateExpression()), sameResource); + Map updatedExps = getUpdateSet(updateFromResource, sameResource); + Type resType = id.getResourceStateType(); + Expression exp = st.getCurStateExpression(); + Type expType = getExpTypeIfUpdatable(resType, exp); + if (expType != null) { + id.setResourceStateType(expType); + for (Expression resExp: sameResource) { + if (resExp != exp) { + if (resExp instanceof Variable && compareTypes(((Variable) resExp).getType(), expType)) { + ((Variable) resExp).setType(expType); + updatedExps.put(System.identityHashCode(resExp), resExp); + } else if (resExp instanceof Term && compareTypes(((Term) resExp).getType(), expType)) { + ((Term) resExp).setType(expType); + updatedExps.put(System.identityHashCode(resExp), resExp); } } } - } else { - for (Edge e: resource.getInEdges()) { - for (ChannelMember cm : ((ResourceDependency) e).getChannelGenerator().getChannelMembers()) { - if (((PushPullAttribute) ((ResourceDependency) e).getAttribute()).getOptions().get(0) == PushPullValue.PUSH - && cm.getStateTransition().getNextStateExpression() instanceof Term) { - updateResourceType(resource, cm); + } else if (exp instanceof Variable) { + if (compareTypes(((Variable) exp).getType(), resType)) { + ((Variable) exp).setType(resType); + updatedExps.put(System.identityHashCode(exp), exp); + } + } else if (exp instanceof Term) { + if (compareTypes(((Term) exp).getType(), resType)) { + ((Term) exp).setType(resType); + updatedExps.put(System.identityHashCode(exp), exp); + } + } + resType = id.getResourceStateType(); + exp = st.getNextStateExpression(); + expType = getExpTypeIfUpdatable(resType, exp); + if (expType != null) { + id.setResourceStateType(expType); + for (Expression resExp: sameResource) { + if (resExp != exp) { + if (resExp instanceof Variable && compareTypes(((Variable) resExp).getType(), expType)) { + ((Variable) resExp).setType(expType); + updatedExps.put(System.identityHashCode(resExp), resExp); + } else if (resExp instanceof Term && compareTypes(((Term) resExp).getType(), expType)) { + ((Term) resExp).setType(expType); + updatedExps.put(System.identityHashCode(resExp), resExp); } - break; + } + } + } else if (exp instanceof Variable) { + if (compareTypes(((Variable) exp).getType(), resType)) { + ((Variable) exp).setType(resType); + updatedExps.put(System.identityHashCode(exp), exp); + } + } else if (exp instanceof Term) { + if (compareTypes(((Term) exp).getType(), resType)) { + ((Term) exp).setType(resType); + updatedExps.put(System.identityHashCode(exp), exp); + } + } + + // Group expressions by variable. + Map> locals = new HashMap<>(); + Map localTypes = new HashMap<>(); + List allVariables = new ArrayList<>(); + allVariables.addAll(st.getCurStateExpression().getVariables().values()); + allVariables.addAll(st.getMessageExpression().getVariables().values()); + allVariables.addAll(st.getNextStateExpression().getVariables().values()); + for (Variable var: allVariables) { + List sameVariable = locals.get(var.getName()); + if (sameVariable == null) { + sameVariable = new ArrayList<>(); + sameVariable.add(var); + expToVariable.put(System.identityHashCode(var), sameVariable); + locals.put(var.getName(), sameVariable); + localTypes.put(var.getName(), var.getType()); + } else { + sameVariable.add(var); + expToVariable.put(System.identityHashCode(var), sameVariable); + Type varType = localTypes.get(var.getName()); + Map updatedVars = getUpdateSet(updateFromVariable, sameVariable); + if (compareTypes(varType, var.getType())) { + localTypes.put(var.getName(), var.getType()); + for (Variable v: sameVariable) { + if (v != var) { + if (compareTypes(v.getType(), var.getType())) { + v.setType(var.getType()); + updatedVars.put(System.identityHashCode(v), v); + } + } + } + } else if (compareTypes(var.getType(), varType)) { + var.setType(varType); + updatedVars.put(System.identityHashCode(var), var); } } } - for (Edge e: resource.getOutEdges()) { - for (ChannelMember cm : ((ResourceDependency) e).getChannelGenerator().getChannelMembers()) { - if (((PushPullAttribute) ((ResourceDependency) e).getAttribute()).getOptions().get(0) != PushPullValue.PUSH - && cm.getStateTransition().getNextStateExpression() instanceof Term) { - updateResourceType(resource, cm); + for (String varName: locals.keySet()) { + variables.put(System.identityHashCode(locals.get(varName)), localTypes.get(varName)); + } + + // Group expressions by message. + Expression message = st.getMessageExpression(); + if (message instanceof Variable) { + Type msgType = ((Variable) message).getType(); + Map, Type>> msgTypeMap = messages.get(c); + if (msgTypeMap == null) { + msgTypeMap = new HashMap<>(); + messages.put(c, msgTypeMap); + } + Map.Entry, Type> typeAndExps = msgTypeMap.get(0); + if (typeAndExps == null) { + List exps = new ArrayList<>(); + exps.add(message); + typeAndExps = new AbstractMap.SimpleEntry<>(exps, msgType); + msgTypeMap.put(0, typeAndExps); + expToMessage.put(System.identityHashCode(message), exps); + } else { + typeAndExps.getKey().add(message); + expToMessage.put(System.identityHashCode(message), typeAndExps.getKey()); + Map updateExps = getUpdateSet(updateFromMessage, typeAndExps.getKey()); + if (compareTypes(typeAndExps.getValue(), msgType)) { + typeAndExps.setValue(msgType); + for (Expression e: typeAndExps.getKey()) { + if (e != message) { + if (e instanceof Variable) { + ((Variable) e).setType(msgType); + updateExps.put(System.identityHashCode(e), e); + } + } + } + } else if (compareTypes(msgType, typeAndExps.getValue())) { + ((Variable) message).setType(typeAndExps.getValue()); + updateExps.put(System.identityHashCode(message), message); + } + } + } else if (message instanceof Term) { + Map, Type>> msgTypeMap = messages.get(c); + if (msgTypeMap == null) { + msgTypeMap = new HashMap<>(); + messages.put(c, msgTypeMap); + } + for (int i = 0; i < ((Term) message).getArity(); i++) { + Expression arg = ((Term) message).getChild(i); + Type argType = null; + if (arg instanceof Variable) { + argType = ((Variable) arg).getType(); + } else if (arg instanceof Term) { + argType = ((Term) arg).getType(); + } else { + continue; + } + Map.Entry, Type> typeAndExps = msgTypeMap.get(i); + if (typeAndExps == null) { + List exps = new ArrayList<>(); + exps.add(arg); + typeAndExps = new AbstractMap.SimpleEntry<>(exps, argType); + msgTypeMap.put(i, typeAndExps); + expToMessage.put(System.identityHashCode(arg), exps); + } else { + typeAndExps.getKey().add(arg); + expToMessage.put(System.identityHashCode(arg), typeAndExps.getKey()); + Map updateExps = getUpdateSet(updateFromMessage, typeAndExps.getKey()); + if (compareTypes(typeAndExps.getValue(), argType)) { + typeAndExps.setValue(argType); + for (Expression e: typeAndExps.getKey()) { + if (e != arg) { + if (e instanceof Variable) { + ((Variable) e).setType(argType); + updateExps.put(System.identityHashCode(e), e); + } + } + } + } else if (compareTypes(argType, typeAndExps.getValue())) { + if (arg instanceof Variable) { + ((Variable) arg).setType(typeAndExps.getValue()); + updateExps.put(System.identityHashCode(arg), arg); + } else if (arg instanceof Term) { + ((Term) arg).setType(typeAndExps.getValue()); + updateExps.put(System.identityHashCode(arg), arg); + } + } + } + } + } + + Collection terms = new HashSet<>(); + if (st.getCurStateExpression() instanceof Term) { + Map subTerms = ((Term) st.getCurStateExpression()).getSubTerms(Term.class); + terms.addAll(subTerms.values()); + } + if (st.getMessageExpression() instanceof Term) { + Map subTerms = ((Term) st.getMessageExpression()).getSubTerms(Term.class); + terms.addAll(subTerms.values()); + } + if (st.getNextStateExpression() instanceof Term) { + Map subTerms = ((Term) st.getNextStateExpression()).getSubTerms(Term.class); + terms.addAll(subTerms.values()); + } + for (Term t: terms) { + if (t.getSymbol().equals(DataConstraintModel.cons)) { + // If the root symbol of the term is cons. + List consExps = new ArrayList<>(); + consExps.add(t); + expToCons.put(System.identityHashCode(t), consExps); + for (Expression e: t.getChildren()) { + consExps.add(e); + expToCons.put(System.identityHashCode(e), consExps); } - break; + Type newType = getExpTypeIfUpdatable(t.getType(), consExps.get(2)); + if (newType != null) { + // If the type of the second argument is more concrete than the type of the term. + t.setType(newType); + Map updateCons = getUpdateSet(updateFromCons, consExps); + updateCons.put(System.identityHashCode(t), t); + } else { + Type arg2Type = null; + if (consExps.get(2) != null && consExps.get(2) instanceof Variable) { + arg2Type = ((Variable) consExps.get(2)).getType(); + if (compareTypes(arg2Type, t.getType())) { + // If the type of the term is more concrete than the type of the second argument. + ((Variable) consExps.get(2)).setType(t.getType()); + Map updateCons = getUpdateSet(updateFromCons, consExps); + updateCons.put(System.identityHashCode(consExps.get(2)), consExps.get(2)); + } + } else if (consExps.get(2) != null && consExps.get(2) instanceof Term) { + arg2Type = ((Term) consExps.get(2)).getType(); + if (compareTypes(arg2Type, t.getType())) { + // If the type of the term is more concrete than the type of the second argument. + ((Term) consExps.get(2)).setType(t.getType()); + Map updateCons = getUpdateSet(updateFromCons, consExps); + updateCons.put(System.identityHashCode(consExps.get(2)), consExps.get(2)); + } + } + } + Type newCompType = getExpTypeIfUpdatable(listComponentTypes.get(t.getType()), consExps.get(1)); + if (newCompType != null) { + // If the type of the first argument is more concrete than the type of list component. + Type newListType = listTypes.get(newCompType); + if (newListType == null) { + // Create new list type. + newListType = createNewListType(newCompType, DataConstraintModel.typeList); + } + t.setType(newListType); + Map updateCons = getUpdateSet(updateFromCons, consExps); + updateCons.put(System.identityHashCode(t), t); + if (consExps.get(2) != null && consExps.get(2) instanceof Variable) { + ((Variable) consExps.get(2)).setType(newListType); + updateCons.put(System.identityHashCode(consExps.get(2)), consExps.get(2)); + } else if (consExps.get(2) != null && consExps.get(2) instanceof Term) { + ((Term) consExps.get(2)).setType(newListType); + updateCons.put(System.identityHashCode(consExps.get(2)), consExps.get(2)); + } + } + cons.put(System.identityHashCode(consExps), t.getType()); + } else if (t.getSymbol().equals(DataConstraintModel.tuple)) { + // If the root symbol of the term is tuple. + List tupleExps = new ArrayList<>(); + List argsTypeList = new ArrayList<>(); + tupleExps.add(t); + expToTuple.put(System.identityHashCode(t), tupleExps); + for (Expression e: t.getChildren()) { + tupleExps.add(e); + expToTuple.put(System.identityHashCode(e), tupleExps); + if (e instanceof Variable) { + argsTypeList.add(((Variable) e).getType()); + } else if (e instanceof Term) { + argsTypeList.add(((Term) e).getType()); + } else { + argsTypeList.add(null); + } + } + if (t.getType() == DataConstraintModel.typeTuple) { + Type newTupleType = tupleTypes.get(argsTypeList); + if (newTupleType == null) { + // Create new tuple type; + newTupleType = createNewTupleType(argsTypeList, DataConstraintModel.typeTuple); + } + t.setType(newTupleType); + Map updateExps = getUpdateSet(updateFromTuple, tupleExps); + updateExps.put(System.identityHashCode(t), t); + } + tuple.put(System.identityHashCode(tupleExps), t.getType()); } } - if (resource.getIdentifierTemplate().getResourceStateType() == null) - resource.getIdentifierTemplate().setResourceStateType(DataConstraintModel.typeInt); + } + } + + // Propagate type information. + while (updateFromResource.size() > 0 || updateFromVariable.size() > 0 || updateFromMessage.size() > 0 || updateFromCons.size() > 0 || updateFromTuple.size() > 0) { + if (updateFromResource.size() > 0) { + Set resourceKeys = updateFromResource.keySet(); + Integer resourceKey = resourceKeys.iterator().next(); + Map resourceValue = updateFromResource.get(resourceKey); + updateFromResource.remove(resourceKey); + for (int i: resourceValue.keySet()) { + Expression resExp = resourceValue.get(i); + updateVaribleTypes(resExp, variables, expToVariable, updateFromVariable); + updateMessageTypes(resExp, messages, expToMessage, updateFromMessage); + updateConsTypes(resExp, cons, expToCons, updateFromCons); + updateTupleTypes(resExp, tuple, expToTuple, updateFromTuple); + } + } + if (updateFromVariable.size() > 0) { + Set variableKeys = updateFromVariable.keySet(); + Integer variableKey = variableKeys.iterator().next(); + Map variableValue = updateFromVariable.get(variableKey); + updateFromVariable.remove(variableKey); + for (int i: variableValue.keySet()) { + Variable var = variableValue.get(i); + updateResourceTypes(var, resources, expToResource, updateFromResource); + updateMessageTypes(var, messages, expToMessage, updateFromMessage); + updateConsTypes(var, cons, expToCons, updateFromCons); + updateTupleTypes(var, tuple, expToTuple, updateFromTuple); + } + } + if (updateFromMessage.size() > 0) { + Set messageKeys = updateFromMessage.keySet(); + Integer messageKey = messageKeys.iterator().next(); + Map messageValue = updateFromMessage.get(messageKey); + updateFromMessage.remove(messageKey); + for (int i: messageValue.keySet()) { + Expression mesExp = messageValue.get(i); + updateResourceTypes(mesExp, resources, expToResource, updateFromResource); + updateVaribleTypes(mesExp, variables, expToVariable, updateFromVariable); + updateConsTypes(mesExp, cons, expToCons, updateFromCons); + updateTupleTypes(mesExp, tuple, expToTuple, updateFromTuple); + } + } + if (updateFromCons.size() > 0) { + Set consKeys = updateFromCons.keySet(); + Integer consKey = consKeys.iterator().next(); + Map consValue = updateFromCons.get(consKey); + updateFromCons.remove(consKey); + for (int i: consValue.keySet()) { + Expression consExp = consValue.get(i); + updateResourceTypes(consExp, resources, expToResource, updateFromResource); + updateVaribleTypes(consExp, variables, expToVariable, updateFromVariable); + updateMessageTypes(consExp, messages, expToMessage, updateFromMessage); + updateTupleTypes(consExp, tuple, expToTuple, updateFromTuple); + } + } + if (updateFromTuple.size() > 0) { + Set tupleKeys = updateFromTuple.keySet(); + Integer tupleKey = tupleKeys.iterator().next(); + Map tupleValue = updateFromTuple.get(tupleKey); + updateFromTuple.remove(tupleKey); + for (int i: tupleValue.keySet()) { + Expression tupleExp = tupleValue.get(i); + updateResourceTypes(tupleExp, resources, expToResource, updateFromResource); + updateVaribleTypes(tupleExp, variables, expToVariable, updateFromVariable); + updateMessageTypes(tupleExp, messages, expToMessage, updateFromMessage); + updateConsTypes(tupleExp, cons, expToCons, updateFromCons); + } + } + } + } + + private static void updateResourceTypes(Expression exp, Map> resources, Map> expToResource, Map> updateFromResource) { + List sameResource = expToResource.get(System.identityHashCode(exp)); + if (sameResource == null) return; + for (IdentifierTemplate id: resources.keySet()) { + if (resources.get(id) == sameResource) { + Type resType = id.getResourceStateType(); + Type newResType = getExpTypeIfUpdatable(resType, exp); + if (newResType != null) { + id.setResourceStateType(newResType); + Map updateExps = getUpdateSet(updateFromResource, sameResource); + for (Expression resExp: sameResource) { + if (resExp != exp) { + if (resExp instanceof Variable) { + ((Variable) resExp).setType(newResType); + updateExps.put(System.identityHashCode(resExp), resExp); + } else if (resExp instanceof Term) { + ((Term) resExp).setType(newResType); + updateExps.put(System.identityHashCode(resExp), resExp); + } + } + } + } } } } - private static void updateResourceType(ResourceNode resource, ChannelMember cm) { - Term rhs = ((Term) cm.getStateTransition().getNextStateExpression()); - if (rhs.getSymbol().equals(DataConstraintModel.cons)) { - Expression listItem = rhs.getChild(0); - if (listItem instanceof Variable) { - Type itemType = null; - if (((Variable) listItem).getType() != null) { - itemType = ((Variable) listItem).getType(); - } else { - if (cm.getStateTransition().getMessageExpression() instanceof Term) { - for (Variable var: ((Term) cm.getStateTransition().getMessageExpression()).getVariables().values()) { - if (((Variable) listItem).getName().equals(var.getName())) { - if (var.getType() != null) { - itemType = var.getType(); - } - } - } - } - if (cm.getStateTransition().getCurStateExpression() instanceof Term) { - for (Variable var: ((Term) cm.getStateTransition().getCurStateExpression()).getVariables().values()) { - if (((Variable) listItem).getName().equals(var.getName())) { - if (var.getType() != null) { - itemType = var.getType(); - } - } - } + private static void updateVaribleTypes(Expression exp, Map variables, Map> expToVariable, Map> updateFromVariable) { + if (exp instanceof Variable) { + Variable var = (Variable) exp; + List sameVariable = expToVariable.get(System.identityHashCode(var)); + if (sameVariable == null) return; + Type varType = variables.get(System.identityHashCode(sameVariable)); + Type newVarType = getExpTypeIfUpdatable(varType, exp); + if (newVarType != null) { + variables.put(System.identityHashCode(sameVariable), newVarType); + Map updateVars = getUpdateSet(updateFromVariable, sameVariable); + for (Variable v: sameVariable) { + if (v != var) { + v.setType(newVarType); + updateVars.put(System.identityHashCode(v), v); } } - if (itemType == DataConstraintModel.typeInt) { - resource.getIdentifierTemplate().setResourceStateType(DataConstraintModel.typeListOfInt); - } else if (itemType == DataConstraintModel.typeFloat) { - resource.getIdentifierTemplate().setResourceStateType(DataConstraintModel.typeListOfFloat); - } else if (itemType == DataConstraintModel.typeDouble) { - resource.getIdentifierTemplate().setResourceStateType(DataConstraintModel.typeListOfDouble); - } else if (itemType == DataConstraintModel.typeString) { - resource.getIdentifierTemplate().setResourceStateType(DataConstraintModel.typeListOfStr); - } else if (itemType == DataConstraintModel.typeList || itemType == DataConstraintModel.typeListOfList) { - resource.getIdentifierTemplate().setResourceStateType(DataConstraintModel.typeListOfList); - } - } else { - resource.getIdentifierTemplate().setResourceStateType(DataConstraintModel.typeList); } } } + + private static void updateMessageTypes(Expression exp, Map, Type>>> messages, Map> expToMessage, Map> updateFromMessage) { + List messageExps = expToMessage.get(System.identityHashCode(exp)); + if (messageExps == null) return; + Type msgType = null; + Map.Entry, Type> expsAndType = null; + for (ChannelGenerator c: messages.keySet()) { + for (int i: messages.get(c).keySet()) { + expsAndType = messages.get(c).get(i); + if (expsAndType.getKey() == messageExps) { + msgType = expsAndType.getValue(); + break; + } + } + if (msgType != null) break; + } + if (msgType == null) return; + Type newMsgType = getExpTypeIfUpdatable(msgType, exp); + if (newMsgType != null) { + expsAndType.setValue(newMsgType); + Map updateExps = getUpdateSet(updateFromMessage, messageExps); + for (Expression e: messageExps) { + if (e != exp) { + if (e instanceof Variable) { + ((Variable) e).setType(newMsgType); + updateExps.put(System.identityHashCode(e), e); + } else if (e instanceof Term) { + ((Term) e).setType(newMsgType); + updateExps.put(System.identityHashCode(e), e); + } + } + } + } + } + + private static void updateConsTypes(Expression exp, Map cons, Map> expToCons, Map> updateFromCons) { + List consComponents = expToCons.get(System.identityHashCode(exp)); + if (consComponents == null) return; + int idx = consComponents.indexOf(exp); + switch (idx) { + case 0: + if (!(exp instanceof Term)) return; + Type listType = cons.get(System.identityHashCode(consComponents)); + Type expType = getExpTypeIfUpdatable(listType, exp); + if (expType != null) { + cons.put(System.identityHashCode(consComponents), expType); + Map updateExps = getUpdateSet(updateFromCons, consComponents); + if (consComponents.get(2) instanceof Variable) { + ((Variable) consComponents.get(2)).setType(expType); + updateExps.put(System.identityHashCode(consComponents.get(2)), consComponents.get(2)); + } else if (consComponents.get(2) instanceof Term) { + ((Term) consComponents.get(2)).setType(expType); + updateExps.put(System.identityHashCode(consComponents.get(2)), consComponents.get(2)); + } + Type compType = listComponentTypes.get(expType); + if (consComponents.get(1) instanceof Variable) { + ((Variable) consComponents.get(1)).setType(compType); + updateExps.put(System.identityHashCode(consComponents.get(1)), consComponents.get(1)); + } else if (consComponents.get(1) instanceof Term) { + ((Term) consComponents.get(1)).setType(compType); + updateExps.put(System.identityHashCode(consComponents.get(1)), consComponents.get(1)); + } + } + break; + case 1: + listType = cons.get(System.identityHashCode(consComponents)); + Type compType = listComponentTypes.get(listType); + Type newCompType = getExpTypeIfUpdatable(compType, exp); + if (newCompType != null) { + Type newListType = listTypes.get(newCompType); + if (newListType == null) { + // Create new list type. + newListType = createNewListType(newCompType, listType); + } + cons.put(System.identityHashCode(consComponents), newListType); + Map updateExps = getUpdateSet(updateFromCons, consComponents); + if (consComponents.get(0) instanceof Term) { + ((Term) consComponents.get(0)).setType(newListType); + updateExps.put(System.identityHashCode(consComponents.get(0)), consComponents.get(0)); + } + if (consComponents.get(2) instanceof Variable) { + ((Variable) consComponents.get(2)).setType(newListType); + updateExps.put(System.identityHashCode(consComponents.get(2)), consComponents.get(2)); + } else if (consComponents.get(2) instanceof Term) { + ((Term) consComponents.get(2)).setType(newListType); + updateExps.put(System.identityHashCode(consComponents.get(2)), consComponents.get(2)); + } + } + break; + case 2: + listType = cons.get(System.identityHashCode(consComponents)); + expType = getExpTypeIfUpdatable(listType, exp); + if (expType != null) { + cons.put(System.identityHashCode(consComponents), expType); + Map updateExps = getUpdateSet(updateFromCons, consComponents); + if (consComponents.get(0) instanceof Term) { + ((Term) consComponents.get(0)).setType(expType); + updateExps.put(System.identityHashCode(consComponents.get(0)), consComponents.get(0)); + } + compType = listComponentTypes.get(expType); + if (consComponents.get(1) instanceof Variable) { + ((Variable) consComponents.get(1)).setType(compType); + updateExps.put(System.identityHashCode(consComponents.get(1)), consComponents.get(1)); + } else if (consComponents.get(1) instanceof Term) { + ((Term) consComponents.get(1)).setType(compType); + updateExps.put(System.identityHashCode(consComponents.get(1)), consComponents.get(1)); + } + } + } + } + + private static Type createNewListType(Type compType, Type parentType) { + String compTypeName = getInterfaceTypeName(compType); + Type newListType = new Type("List", "ArrayList<>", "List<" + compTypeName + ">", parentType); + listTypes.put(compType, newListType); + listComponentTypes.put(newListType, compType); + return newListType; + } + + private static void updateTupleTypes(Expression exp, Map tuple, Map> expToTuple, Map> updateFromTuple) { + List components = expToTuple.get(System.identityHashCode(exp)); + if (components == null) return; + int idx = components.indexOf(exp); + if (idx == 0) { + Type tupleType = tuple.get(System.identityHashCode(components)); + Type newTupleType = getExpTypeIfUpdatable(tupleType, exp); + if (newTupleType != null) { + tuple.put(System.identityHashCode(components), newTupleType); + List componentTypes = tupleComponentTypes.get(newTupleType); + Map updateExps = getUpdateSet(updateFromTuple, components); + for (int i = 0; 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)); + 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)); + updateExps.put(System.identityHashCode(compExp), compExp); + } + } + } + } + } else { + Type tupleType = tuple.get(System.identityHashCode(components)); + List componentTypes = tupleComponentTypes.get(tupleType); + Type compType = componentTypes.get(idx - 1); + Type newCompType = getExpTypeIfUpdatable(compType, exp); + if (newCompType != null) { + componentTypes = new ArrayList<>(componentTypes); + componentTypes.set(idx - 1, newCompType); + Type newTupleType = tupleTypes.get(componentTypes); + if (newTupleType == null) { + // 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); + tuple.put(System.identityHashCode(components), newTupleType); + } + } + } + + private static Type createNewTupleType(List componentTypes, Type parentTupleType) { + String implTypeName = "AbstractMap.SimpleEntry<>"; + String interfaceTypeName = "Map.Entry<$x>"; + if (componentTypes.size() >= 2) { + implTypeName = implTypeName.replace("$x", getImplementationTypeName(componentTypes.get(0))+ "$x"); + interfaceTypeName = interfaceTypeName.replace("$x", getInterfaceTypeName(componentTypes.get(0)) + "$x"); + for (Type argType: componentTypes.subList(1, componentTypes.size() - 1)) { + implTypeName = implTypeName.replace("$x", ", AbstractMap.SimpleEntry<" + getImplementationTypeName(argType)+ "$x>"); + interfaceTypeName = interfaceTypeName.replace("$x", ", Map.Entry<" + getInterfaceTypeName(argType) + "$x>"); + } + implTypeName = implTypeName.replace("$x", ", " + getImplementationTypeName(componentTypes.get(componentTypes.size() - 1))); + interfaceTypeName = interfaceTypeName.replace("$x", ", " + getInterfaceTypeName(componentTypes.get(componentTypes.size() - 1))); + } + Type newTupleType = new Type("Tuple", implTypeName, interfaceTypeName, parentTupleType); + tupleTypes.put(componentTypes, newTupleType); + tupleComponentTypes.put(newTupleType, componentTypes); + return newTupleType; + } + + private static String getImplementationTypeName(Type type) { + if (type == null) return "Integer"; + return wrapperType(type.getImplementationTypeName()); + } + + private static String getInterfaceTypeName(Type type) { + if (type == null) return "Integer"; + return wrapperType(type.getInterfaceTypeName()); + } + + private static String wrapperType(String implTypeName) { + if (implTypeName.equals(DataConstraintModel.typeInt.getImplementationTypeName())) { + implTypeName = "Integer"; + } else if (implTypeName.equals(DataConstraintModel.typeLong.getImplementationTypeName())) { + implTypeName = "Long"; + } else if (implTypeName.equals(DataConstraintModel.typeFloat.getImplementationTypeName())) { + implTypeName = "Float"; + } else if (implTypeName.equals(DataConstraintModel.typeDouble.getImplementationTypeName())) { + implTypeName = "Double"; + } else if (implTypeName.equals(DataConstraintModel.typeBoolean.getImplementationTypeName())) { + implTypeName = "Boolean"; + } + return implTypeName; + } + + private static > Map getUpdateSet(Map> updateSets, U keySet) { + Map updatedExps = updateSets.get(System.identityHashCode(keySet)); + if (updatedExps == null) { + updatedExps = new HashMap<>(); + updateSets.put(System.identityHashCode(keySet), updatedExps); + } + return updatedExps; + } + + private static Type getExpTypeIfUpdatable(Type originalType, Expression newExp) { + Type expType = null; + if (newExp instanceof Term) { + expType = ((Term) newExp).getType(); + } else if (newExp instanceof Variable) { + expType = ((Variable) newExp).getType(); + } + if (compareTypes(originalType, expType)) { + return expType; + } + return null; + } + + private static boolean compareTypes(Type originalType, Type newType) { + if (originalType == null || (originalType != newType && newType != null && originalType.isAncestorOf(newType))) { + return true; + } + return false; + } } diff --git a/AlgebraicDataflowArchitectureModel/src/models/algebra/Symbol.java b/AlgebraicDataflowArchitectureModel/src/models/algebra/Symbol.java index 5455843..ac91474 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/algebra/Symbol.java +++ b/AlgebraicDataflowArchitectureModel/src/models/algebra/Symbol.java @@ -3,7 +3,7 @@ public class Symbol { private String name; private String implName; - private int arity = 0; + private int arity = 0; // -1: variable number private Type operatorType = Type.PREFIX; private Type implOperatorType = Type.PREFIX; private Symbol[] inverses = null; diff --git a/AlgebraicDataflowArchitectureModel/src/models/algebra/Term.java b/AlgebraicDataflowArchitectureModel/src/models/algebra/Term.java index ecd85a4..d468d09 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/algebra/Term.java +++ b/AlgebraicDataflowArchitectureModel/src/models/algebra/Term.java @@ -7,6 +7,7 @@ public class Term extends Expression { protected Symbol symbol = null; protected ArrayList children = new ArrayList<>(); + protected Type type = null; public Term(Symbol symbol) { super(); @@ -26,15 +27,27 @@ public int getArity() { return symbol.getArity(); } + + public void setType(Type type) { + this.type = type; + } + + public Type getType() { + if (type == null) { + if (symbol.getSignature() == null) return null; + return symbol.getSignature()[0]; + } + return type; + } public boolean addChild(Expression child) { - if (children.size() >= getArity()) return false; + if (getArity() != -1 && children.size() >= getArity()) return false; children.add(child); return true; } public void addChild(Expression child, boolean bForced) { - if (!bForced && children.size() >= getArity()) return; + if (!bForced && getArity() != -1 && children.size() >= getArity()) return; children.add(child); } @@ -143,6 +156,7 @@ Term anotherTerm = (Term) another; if (!symbol.equals(anotherTerm.symbol)) return false; if (children.size() != anotherTerm.children.size()) return false; + if (type != anotherTerm.type) return false; for (int i = 0; i < children.size(); i++) { Expression e = children.get(i); Expression e2 = anotherTerm.children.get(i); @@ -163,6 +177,7 @@ for (Expression e: children) { newTerm.addChild((Expression) e.clone()); } + newTerm.type = type; return newTerm; } diff --git a/AlgebraicDataflowArchitectureModel/src/models/algebra/Type.java b/AlgebraicDataflowArchitectureModel/src/models/algebra/Type.java index 7241bed..38e5598 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/algebra/Type.java +++ b/AlgebraicDataflowArchitectureModel/src/models/algebra/Type.java @@ -4,6 +4,7 @@ private String typeName; private String implementationTypeName; private String interfaceTypeName; + private Type parentType = null; public Type(String typeName, String implementastionTypeName) { this.typeName = typeName; @@ -16,6 +17,13 @@ this.implementationTypeName = implementastionTypeName; this.interfaceTypeName = interfaceTypeName; } + + public Type(String typeName, String implementastionTypeName, String interfaceTypeName, Type parentType) { + this.typeName = typeName; + this.implementationTypeName = implementastionTypeName; + this.interfaceTypeName = interfaceTypeName; + this.parentType = parentType; + } public String getTypeName() { return typeName; @@ -41,22 +49,39 @@ this.interfaceTypeName = interfaceTypeName; } + public Type getParentType() { + return parentType; + } + + public void setParentType(Type parentType) { + this.parentType = parentType; + } + + public boolean isAncestorOf(Type another) { + if (this.equals(another)) return true; + if (another.getParentType() == null) return false; + return isAncestorOf(another.getParentType()); + } + public Memento createMemento() { - return new Memento(implementationTypeName, interfaceTypeName); + return new Memento(implementationTypeName, interfaceTypeName, parentType); } public void setMemento(Memento memento) { this.implementationTypeName = memento.implementationTypeName; this.interfaceTypeName = memento.interfaceTypeName; + this.parentType = memento.parentType; } public static class Memento { private String implementationTypeName; private String interfaceTypeName; + private Type parentType; - public Memento(String implementationTypeName, String interfaceTypeName) { + public Memento(String implementationTypeName, String interfaceTypeName, Type parentType) { this.implementationTypeName = implementationTypeName; this.interfaceTypeName = interfaceTypeName; + this.parentType = parentType; } } } diff --git a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/DataConstraintModel.java b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/DataConstraintModel.java index f3a0b57..7599d14 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/DataConstraintModel.java +++ b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/DataConstraintModel.java @@ -16,30 +16,36 @@ protected HashMap types = null; protected HashMap symbols = null; public static final Type typeInt = new Type("Int", "int"); + public static final Type typeLong = new Type("Long", "long"); public static final Type typeFloat = new Type("Float", "float"); public static final Type typeDouble = new Type("Double", "double"); public static final Type typeBoolean = new Type("Bool", "boolean"); public static final Type typeString = new Type("Str", "String"); public static final Type typeList = new Type("List", "ArrayList", "List"); - public static final Type typeListOfStr = new Type("List", "ArrayList", "List"); - public static final Type typeListOfInt = new Type("List", "ArrayList", "List"); - public static final Type typeListOfFloat = new Type("List", "ArrayList", "List"); - public static final Type typeListOfDouble = new Type("List", "ArrayList", "List"); - public static final Type typeListOfList = new Type("List", "ArrayList", "List"); +// public static final Type typeListOfStr = new Type("List", "ArrayList", "List", typeList); +// public static final Type typeListOfInt = new Type("List", "ArrayList", "List", typeList); +// public static final Type typeListOfFloat = new Type("List", "ArrayList", "List", typeList); +// public static final Type typeListOfDouble = new Type("List", "ArrayList", "List", typeList); +// public static final Type typeListOfList = new Type("List", "ArrayList", "List", typeList); +// public static final Type typeListOfTuple = new Type("List", "ArrayList", "List", typeList); + public static final Type typeTuple = new Type("Tuple", "AbstractMap.SimpleEntry", "Map.Entry"); public static final Symbol add = new Symbol(Parser.ADD, 2, Symbol.Type.INFIX); public static final Symbol mul = new Symbol(Parser.MUL, 2, Symbol.Type.INFIX);; public static final Symbol sub = new Symbol(Parser.SUB, 2, Symbol.Type.INFIX); public static final Symbol div = new Symbol(Parser.DIV, 2, Symbol.Type.INFIX); public static final Symbol minus = new Symbol(Parser.MINUS, 1); public static final Symbol cons = new Symbol("cons", 2, Symbol.Type.PREFIX, "add", Symbol.Type.METHOD_WITH_SIDE_EFFECT, new int[] {1, 0}); - public static final Symbol head = new Symbol("head", 1, Symbol.Type.PREFIX, "get(0)", Symbol.Type.METHOD); - public static final Symbol body = new Symbol("tail", 1, Symbol.Type.PREFIX, "($x)->$x.subString(1, $x.size())", Symbol.Type.LAMBDA); + public static final Symbol head = new Symbol("head", 1, Symbol.Type.PREFIX, "($x)->$x.get(0)", Symbol.Type.LAMBDA); + public static final Symbol tail = new Symbol("tail", 1, Symbol.Type.PREFIX, "($x)->$x.subList(1, $x.size())", Symbol.Type.LAMBDA); public static final Symbol contains = new Symbol("contains", 2, Symbol.Type.PREFIX, "contains", Symbol.Type.METHOD); public static final Symbol cond = new Symbol("if", 3, Symbol.Type.PREFIX, "($x,$y,$z)->($x ? $y : $z)", Symbol.Type.LAMBDA); public static final Symbol eq = new Symbol("eq", 2, Symbol.Type.PREFIX, "==", Symbol.Type.INFIX); public static final Symbol neq = new Symbol("neq", 2, Symbol.Type.PREFIX, "!=", Symbol.Type.INFIX); public static final Symbol gt = new Symbol("gt", 2, Symbol.Type.PREFIX, ">", Symbol.Type.INFIX); public static final Symbol lt = new Symbol("lt", 2, Symbol.Type.PREFIX, "<", Symbol.Type.INFIX); + public static final Symbol tuple = new Symbol("tuple", -1, Symbol.Type.PREFIX, "new AbstractMap.SimpleEntry<>", Symbol.Type.PREFIX); + public static final Symbol fst = new Symbol("fst", 1, Symbol.Type.PREFIX, "getKey", Symbol.Type.METHOD); + public static final Symbol snd = new Symbol("snd", 1, Symbol.Type.PREFIX, "getValue", Symbol.Type.METHOD); static { add.setInverses(new Symbol[] {sub, sub}); @@ -47,9 +53,13 @@ sub.setInverses(new Symbol[] {add}); div.setInverses(new Symbol[] {mul}); minus.setInverses(new Symbol[] {minus}); - cons.setInverses(new Symbol[] {head, body}); + cons.setInverses(new Symbol[] {head, tail}); cons.setSignature(new Type[] {typeList, null, typeList}); - contains.setSignature(new Type[] {typeList, null}); + contains.setSignature(new Type[] {typeBoolean, typeList, null}); + tuple.setSignature(new Type[] {typeTuple, null, null}); + tuple.setInverses(new Symbol[] {fst, snd}); + fst.setSignature(new Type[] {null, typeTuple}); + snd.setSignature(new Type[] {null, typeTuple}); } public DataConstraintModel() { @@ -58,11 +68,13 @@ ioChannelGenerators = new HashMap<>(); types = new HashMap<>(); addType(typeInt); + addType(typeLong); addType(typeFloat); addType(typeDouble); addType(typeBoolean); addType(typeString); addType(typeList); + addType(typeTuple); symbols = new HashMap<>(); addSymbol(add); addSymbol(mul); @@ -71,13 +83,16 @@ addSymbol(minus); addSymbol(cons); addSymbol(head); - addSymbol(body); + addSymbol(tail); addSymbol(contains); addSymbol(cond); addSymbol(eq); addSymbol(neq); addSymbol(gt); addSymbol(lt); + addSymbol(tuple); + addSymbol(fst); + addSymbol(snd); } public Collection getIdentifierTemplates() { @@ -169,12 +184,6 @@ } public static boolean isListType(Type type) { - if (type == typeList) return true; - if (type == typeListOfInt) return true; - if (type == typeListOfFloat) return true; - if (type == typeListOfDouble) return true; - if (type == typeListOfStr) return true; - if (type == typeListOfList) return true; - return false; + return typeList.isAncestorOf(type); } }