diff --git a/AlgebraicDataflowArchitectureModel/src/algorithms/TypeInference.java b/AlgebraicDataflowArchitectureModel/src/algorithms/TypeInference.java deleted file mode 100644 index f57b895..0000000 --- a/AlgebraicDataflowArchitectureModel/src/algorithms/TypeInference.java +++ /dev/null @@ -1,2402 +0,0 @@ -package algorithms; - -import java.util.AbstractMap; -import java.util.ArrayList; -import java.util.Arrays; -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 javax.xml.crypto.Data; - -import models.Node; -import models.algebra.Constant; -import models.algebra.Expression; -import models.algebra.Position; -import models.algebra.Symbol; -import models.algebra.Term; -import models.algebra.Type; -import models.algebra.Variable; -import models.dataConstraintModel.Channel; -import models.dataConstraintModel.ChannelMember; -import models.dataConstraintModel.DataConstraintModel; -import models.dataConstraintModel.JsonType; -import models.dataConstraintModel.ResourceHierarchy; -import models.dataConstraintModel.ResourcePath; -import models.dataConstraintModel.Selector; -import models.dataConstraintModel.StateTransition; -import models.dataFlowModel.DataTransferModel; -import models.dataFlowModel.ResourceNode; - -/** - * Type inference for data transfer model - * - * @author Nitta - * - */ -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 private Map pairTypes = new HashMap<>(); - static private Map pairComponentTypes = new HashMap<>(); - static private Map, Type> mapTypes = new HashMap<>(); - static private Map> mapComponentTypes = new HashMap<>(); - static private Map, Type> jsonTypes = new HashMap<>(); - static private Map> jsonMemberTypes = new HashMap<>(); - - public static Type getListType(Type compType) { - return listTypes.get(compType); - } - - public static Type getListComponentType(Type listType) { - return listComponentTypes.get(listType); - } - - public static Collection getListTypes() { - return listTypes.values(); - } - - public static Type getTupleType(List compTypes) { - return tupleTypes.get(compTypes); - } - - public static List getTupleComponentTypes(Type tupleType) { - return tupleComponentTypes.get(tupleType); - } - - public static Collection getTupleTypes() { - return tupleTypes.values(); - } - - public static Type getPairType(Type compType) { - return pairTypes.get(compType); - } - - public static Type getPairComponentType(Type pairType) { - return pairComponentTypes.get(pairType); - } - - public static Type getMapType(List compTypes) { - return mapTypes.get(compTypes); - } - - public static List getMapComponentTypes(Type mapType) { - return mapComponentTypes.get(mapType); - } - - public static Type getJsonType(Map memberTypes) { - return jsonTypes.get(memberTypes); - } - - public static Map getJsonMemberTypes(Type jsonType) { - return jsonMemberTypes.get(jsonType); - } - - static public void infer(DataTransferModel model) { - Map> resources = new HashMap<>(); - Map> resourcePathParams = new HashMap<>(); - Map variables = new HashMap<>(); - Map, Type>>> messages = new HashMap<>(); - Map consOrSet = new HashMap<>(); - Map tuple = new HashMap<>(); - Map pair = new HashMap<>(); - Map map = new HashMap<>(); - Map json = new HashMap<>(); - - // Maps from the objectId of each expression to its belonging group that has the same type as the expression - Map> expToResource = new HashMap<>(); - Map> expToPathParams = new HashMap<>(); - Map> expToVariable = new HashMap<>(); - Map> expToMessage = new HashMap<>(); - Map>> expToConsOrSet = new HashMap<>(); - Map>> expToTuple = new HashMap<>(); - Map>> expToPair = new HashMap<>(); - Map>> expToMap = new HashMap<>(); - Map>> expToJson = new HashMap<>(); - - // Maps from the objectId of each group to the set of updated expressions. - Map> updateFromResource = new HashMap<>(); - Set updateFromResourceOwnership = new HashSet<>(); - Map> updateFromVariable = new HashMap<>(); - Map> updateFromMessage = new HashMap<>(); - Map> updateFromConsOrSet = new HashMap<>(); - Map> updateFromTuple = new HashMap<>(); - Map> updateFromPair = new HashMap<>(); - Map> updateFromMap = new HashMap<>(); - Map> updateFromJson = new HashMap<>(); - - listComponentTypes.put(DataConstraintModel.typeList, null); - listComponentTypes.put(DataConstraintModel.typeListInt, DataConstraintModel.typeInt); - listComponentTypes.put(DataConstraintModel.typeListStr, DataConstraintModel.typeString); - listTypes.put(DataConstraintModel.typeInt, DataConstraintModel.typeListInt); - listTypes.put(DataConstraintModel.typeString, DataConstraintModel.typeListStr); - pairComponentTypes.put(DataConstraintModel.typePair, null); - pairComponentTypes.put(DataConstraintModel.typePairInt, DataConstraintModel.typeInt); - pairComponentTypes.put(DataConstraintModel.typePairStr, DataConstraintModel.typeString); - pairComponentTypes.put(DataConstraintModel.typePairDouble, DataConstraintModel.typeDouble); - pairTypes.put(DataConstraintModel.typeInt, DataConstraintModel.typePairInt); - pairTypes.put(DataConstraintModel.typeString, DataConstraintModel.typePairStr); - pairTypes.put(DataConstraintModel.typeDouble, DataConstraintModel.typePairDouble); - tupleComponentTypes.put(DataConstraintModel.typeTuple, Arrays.asList(new Type[] { null, null })); - mapComponentTypes.put(DataConstraintModel.typeMap, Arrays.asList(new Type[] { null, null })); - - // 1. Collect type information from the architecture model. - Collection channels = new HashSet<>(model.getInputChannels()); - channels.addAll(model.getChannels()); - for (Channel ch : channels) { - // 1.1 Group expressions by resources. - IGroupExpressionsByResource groupExpressionsByResource = new IGroupExpressionsByResource() { - public void groupForChannel(Channel ch) { - for (ChannelMember cm : ch.getChannelMembers()) { - StateTransition st = cm.getStateTransition(); - ResourceHierarchy res = cm.getResource().getResourceHierarchy(); - List identicalResources = resources.get(res); - if (identicalResources == null) { - identicalResources = new ArrayList<>(); - resources.put(res, identicalResources); - } - identicalResources.add(st.getCurStateExpression()); - expToResource.put(System.identityHashCode(st.getCurStateExpression()), identicalResources); - if (st.getNextStateExpression() != null) { - identicalResources.add(st.getNextStateExpression()); - expToResource.put(System.identityHashCode(st.getNextStateExpression()), identicalResources); - } - Map updatedExps = getUpdateSet(updateFromResource, identicalResources); - Type resType = res.getResourceStateType(); - Expression exp = st.getCurStateExpression(); - Type expType = getExpTypeIfUpdatable(resType, exp); - if (expType != null) { - res.setResourceStateType(expType); - for (Expression resExp : identicalResources) { - 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 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 = res.getResourceStateType(); - exp = st.getNextStateExpression(); - if (exp != null) { - expType = getExpTypeIfUpdatable(resType, exp); - if (expType != null) { - res.setResourceStateType(expType); - for (Expression resExp : identicalResources) { - 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 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); - } - } - } - } - for (Channel childCh: ch.getChildren()) { - groupForChannel(childCh); - } - } - }; - groupExpressionsByResource.groupForChannel(ch); - - // 1.2 Group expressions by variable. - IGroupExpressionsByVariable groupExpressionsByVariable = new IGroupExpressionsByVariable() { - public void groupForChannel(Channel ch) { - for (ChannelMember cm : ch.getChannelMembers()) { - StateTransition st = cm.getStateTransition(); - Map> locals = new HashMap<>(); - Map localTypes = new HashMap<>(); - List allVariables = new ArrayList<>(); - allVariables.addAll(st.getCurStateExpression().getVariables().values()); - allVariables.addAll(st.getMessageExpression().getVariables().values()); - if (st.getNextStateExpression() != null) { - allVariables.addAll(st.getNextStateExpression().getVariables().values()); - } - for (Selector s: ch.getAllSelectors()) { // add channel selectors - if (s.getExpression() instanceof Variable) { - allVariables.add((Variable) s.getExpression()); - } - } - ResourcePath resPath = cm.getResource(); - for (Expression param: resPath.getPathParams()) { // add path parameters - if (param instanceof Variable) { - allVariables.add((Variable) param); - } else if (param instanceof Term) { - allVariables.addAll(((Term) param).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 (Expression v : sameVariable) { - if (v != var) { - if (compareTypes(((Variable) v).getType(), var.getType())) { - ((Variable) 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 (String varName : locals.keySet()) { - variables.put(System.identityHashCode(locals.get(varName)), localTypes.get(varName)); - } - } - for (Channel childCh: ch.getChildren()) { - groupForChannel(childCh); - } - } - }; - groupExpressionsByVariable.groupForChannel(ch); - - // 1.3 Group expressions by message. - IGroupExpressionsByMessage groupExpressionsByMessage = new IGroupExpressionsByMessage() { - public void groupForChannel(Channel rootCh, Channel ch) { - for (ChannelMember cm : ch.getChannelMembers()) { - Expression message = cm.getStateTransition().getMessageExpression(); - if (message instanceof Variable) { - Type msgType = ((Variable) message).getType(); - Map, Type>> msgTypeMap = messages.get(rootCh); - if (msgTypeMap == null) { - msgTypeMap = new HashMap<>(); - messages.put(rootCh, 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(rootCh); - if (msgTypeMap == null) { - msgTypeMap = new HashMap<>(); - messages.put(rootCh, 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); - } - } - } - } - } - } - for (Channel childCh: ch.getChildren()) { - groupForChannel(rootCh, childCh); - } - } - }; - groupExpressionsByMessage.groupForChannel(ch, ch); - - // 1.4 Extract constraints on expressions in each term. - IExtractConstraintsOnExpressionsInTerm extractConstraintsOnExpressionsInTerm = new IExtractConstraintsOnExpressionsInTerm() { - public void extractForChannel(Channel ch) { - for (ChannelMember cm : ch.getChannelMembers()) { - StateTransition st = cm.getStateTransition(); - List terms = new ArrayList<>(); - 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() != null && st.getNextStateExpression() instanceof Term) { - Map subTerms = ((Term) st.getNextStateExpression()).getSubTerms(Term.class); - terms.addAll(subTerms.values()); - } - for (Term t : terms) { - Symbol symbol = t.getSymbol(); - if (symbol.equals(DataConstraintModel.cons) || symbol.equals(DataConstraintModel.set) || symbol.equals(DataConstraintModel.append)) { - // If the root symbol of the term is cons or set. - List consExps = new ArrayList<>(); - consExps.add(t); // list term - updateExpressionBelonging(expToConsOrSet, t, consExps); - if (symbol.equals(DataConstraintModel.cons)) { - // If the root symbol of the term is cons. - for (Expression e : t.getChildren()) { - consExps.add(e); - updateExpressionBelonging(expToConsOrSet, e, consExps); - } - } else if (symbol.equals(DataConstraintModel.append)) { - // If the root symbol of the term is append. - Expression e = t.getChildren().get(1); - consExps.add(e); // list element - updateExpressionBelonging(expToConsOrSet, e, consExps); - e = t.getChildren().get(0); - consExps.add(e); // list argument - updateExpressionBelonging(expToConsOrSet, e, consExps); - } else { - // If the root symbol of the term is set. - Expression e = t.getChildren().get(2); - consExps.add(e); // list element - updateExpressionBelonging(expToConsOrSet, e, consExps); - e = t.getChildren().get(0); - consExps.add(e); // list argument - updateExpressionBelonging(expToConsOrSet, e, consExps); - } - Type newType = getExpTypeIfUpdatable(t.getType(), consExps.get(2)); - if (newType != null) { - // If the type of the 2nd argument of cons (1st argument of set/append) is more concrete than the type of the term. - t.setType(newType); - Map updateCons = getUpdateSet(updateFromConsOrSet, 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 2nd argument of cons (1st argument of set/append). - ((Variable) consExps.get(2)).setType(t.getType()); - Map updateCons = getUpdateSet(updateFromConsOrSet, 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 2nd argument of cons (1st argument of set/append). - ((Term) consExps.get(2)).setType(t.getType()); - Map updateCons = getUpdateSet(updateFromConsOrSet, 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 1st argument of cons (3rd argument of set) 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(updateFromConsOrSet, 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)); - } - } - consOrSet.put(System.identityHashCode(consExps), t.getType()); - } else if (symbol.equals(DataConstraintModel.head) || symbol.equals(DataConstraintModel.get)) { - // If the root symbol of the term is head or get. - List consExps = new ArrayList<>(); - Expression e = t.getChildren().get(0); - consExps.add(e); // list argument - updateExpressionBelonging(expToConsOrSet, e, consExps); - consExps.add(t); // list's component - updateExpressionBelonging(expToConsOrSet, t, consExps); - consExps.add(null); - Type listType = listTypes.get(t.getType()); - if (listType == null && t.getType() != null) { - // Create a new list type. - listType = createNewListType(t.getType(), DataConstraintModel.typeList); - } - Type newListType = getExpTypeIfUpdatable(listType, consExps.get(0)); - if (newListType != null) { - // If the type of the component of the 1st argument is more concrete than the type of the term. - Type newCompType = listComponentTypes.get(newListType); - if (newCompType != null) { - t.setType(newCompType); - Map updateCons = getUpdateSet(updateFromConsOrSet, consExps); - updateCons.put(System.identityHashCode(t), t); - } - consOrSet.put(System.identityHashCode(consExps), newListType); - } else { - // If the type of the term is more concrete than the type of the component of the 1st argument. - if (consExps.get(0) != null && consExps.get(0) instanceof Variable) { - ((Variable) consExps.get(0)).setType(listType); - Map updateCons = getUpdateSet(updateFromConsOrSet, consExps); - updateCons.put(System.identityHashCode(consExps.get(0)), consExps.get(0)); - } else if (consExps.get(0) != null && consExps.get(0) instanceof Term) { - ((Term) consExps.get(0)).setType(listType); - Map updateCons = getUpdateSet(updateFromConsOrSet, consExps); - updateCons.put(System.identityHashCode(consExps.get(0)), consExps.get(0)); - } - consOrSet.put(System.identityHashCode(consExps), listType); - } - } else if (symbol.equals(DataConstraintModel.tail)) { - // If the root symbol of the term is tail. - List consExps = new ArrayList<>(); - consExps.add(t); // list term - updateExpressionBelonging(expToConsOrSet, t, consExps); - consExps.add(null); // list's component - Expression e = t.getChildren().get(0); - consExps.add(e); // list argument - updateExpressionBelonging(expToConsOrSet, e, consExps); - Type newType = getExpTypeIfUpdatable(t.getType(), consExps.get(2)); - if (newType != null) { - // If the type of the argument is more concrete than the type of the term. - t.setType(newType); - Map updateCons = getUpdateSet(updateFromConsOrSet, consExps); - updateCons.put(System.identityHashCode(t), t); - } else { - Type argType = null; - if (consExps.get(2) != null && consExps.get(2) instanceof Variable) { - argType = ((Variable) consExps.get(2)).getType(); - if (compareTypes(argType, t.getType())) { - // If the type of the term is more concrete than the type of the argument. - ((Variable) consExps.get(2)).setType(t.getType()); - Map updateCons = getUpdateSet(updateFromConsOrSet, consExps); - updateCons.put(System.identityHashCode(consExps.get(2)), consExps.get(2)); - } - } else if (consExps.get(2) != null && consExps.get(2) instanceof Term) { - argType = ((Term) consExps.get(2)).getType(); - if (compareTypes(argType, t.getType())) { - // If the type of the term is more concrete than the type of the argument. - ((Term) consExps.get(2)).setType(t.getType()); - Map updateCons = getUpdateSet(updateFromConsOrSet, consExps); - updateCons.put(System.identityHashCode(consExps.get(2)), consExps.get(2)); - } - } - } - consOrSet.put(System.identityHashCode(consExps), t.getType()); - } else if (symbol.equals(DataConstraintModel.tuple)) { - // If the root symbol of the term is tuple. - List tupleExps = new ArrayList<>(); - List newArgTypesList = new ArrayList<>(); - tupleExps.add(t); // tuple term - updateExpressionBelonging(expToTuple, t, tupleExps); - for (Expression e : t.getChildren()) { - tupleExps.add(e); // tuple's component - updateExpressionBelonging(expToTuple, e, tupleExps); - if (e instanceof Variable) { - newArgTypesList.add(((Variable) e).getType()); - } else if (e instanceof Term) { - newArgTypesList.add(((Term) e).getType()); - } else { - newArgTypesList.add(null); - } - } - if (t.getType() == DataConstraintModel.typeTuple) { - Type newTupleType = tupleTypes.get(newArgTypesList); - if (newTupleType == null) { - // Create new tuple type; - newTupleType = createNewTupleType(newArgTypesList, DataConstraintModel.typeTuple); - } - // Update the type of the tuple term and record the updated expression. - t.setType(newTupleType); - Map updateExps = getUpdateSet(updateFromTuple, tupleExps); - updateExps.put(System.identityHashCode(t), t); - } - tuple.put(System.identityHashCode(tupleExps), t.getType()); - } else if (symbol.equals(DataConstraintModel.pair)) { - // If the root symbol of the term is pair. - List pairExps = new ArrayList<>(); - pairExps.add(t); // pair - updateExpressionBelonging(expToPair, t, pairExps); - if (t.getType() == DataConstraintModel.typePair) { - for (Expression e : t.getChildren()) { - pairExps.add(e); // left/right - updateExpressionBelonging(expToPair, e, pairExps); - Type newArgType = null; - if (e instanceof Variable) { - newArgType = (((Variable) e).getType()); - - } else if (e instanceof Term) { - newArgType = (((Term) e).getType()); - } - - if (newArgType != null) { - Type newPairType = pairTypes.get(newArgType); - if (newPairType != null) { - t.setType(newPairType); - Map updateExps = getUpdateSet(updateFromPair, pairExps); - updateExps.put(System.identityHashCode(t), t); - } - } - } - pair.put(System.identityHashCode(pairExps), 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); // tuple argument - updateExpressionBelonging(expToTuple, arg, tupleExps); - tupleExps.add(t); // first component - updateExpressionBelonging(expToTuple, t, tupleExps); - tupleExps.add(null); // second component - 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 newCompTypeList = new ArrayList<>(); - newCompTypeList.add(t.getType()); - newCompTypeList.add(null); - newTupleType = tupleTypes.get(newCompTypeList); - if (newTupleType == null) { - // Create new tuple type; - newTupleType = createNewTupleType(newCompTypeList, DataConstraintModel.typeTuple); - } - } - if (argType != newTupleType && newTupleType != null) { - // Update the type of the tuple argument and record the updated expression. - 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); // tuple argument - updateExpressionBelonging(expToTuple, arg, tupleExps); - tupleExps.add(null); // first component - tupleExps.add(t); // second component - updateExpressionBelonging(expToTuple, 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 newCompTypeList = new ArrayList<>(); - newCompTypeList.add(null); - if (DataConstraintModel.typeTuple.isAncestorOf(t.getType())) { - List sndTypes = tupleComponentTypes.get(t.getType()); - if (sndTypes != null) { - for (Type t2: sndTypes) { - newCompTypeList.add(t2); - } - } else { - newCompTypeList.add(t.getType()); - } - } else { - newCompTypeList.add(t.getType()); - } - newTupleType = tupleTypes.get(newCompTypeList); - if (newTupleType == null) { - // Create new tuple type; - newTupleType = createNewTupleType(newCompTypeList, DataConstraintModel.typeTuple); - } - } - if (argType != newTupleType && newTupleType != null) { - // Update the type of the tuple argument and record the updated expression. - 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.left)) { - // If the root symbol of the term is left. - List pairExps = new ArrayList<>(); - Expression arg = t.getChildren().get(0); - pairExps.add(arg); // pair - updateExpressionBelonging(expToPair, arg, pairExps); - pairExps.add(t); // left - updateExpressionBelonging(expToPair, t, pairExps); - pairExps.add(null); // right - Type argType = null; - if (arg instanceof Variable) { - argType = ((Variable) arg).getType(); - } else if (arg instanceof Term) { - argType = ((Term) arg).getType(); - } - Type newPairType = DataConstraintModel.typePair; - if (argType == DataConstraintModel.typePair && t.getType() != null) { - List newCompTypeList = new ArrayList<>(); - newCompTypeList.add(t.getType()); - newCompTypeList.add(null); - newPairType = pairTypes.get(newCompTypeList); - if (newPairType == null) { - // Create new tuple type; - newPairType = createNewTupleType(newCompTypeList, DataConstraintModel.typePair); - } - } - if (argType != newPairType && newPairType != null) { - if (arg instanceof Variable) { - ((Variable) arg).setType(newPairType); - argType = newPairType; - } else if (arg instanceof Term) { - ((Term) arg).setType(newPairType); - argType = newPairType; - } - Map updateExps = getUpdateSet(updateFromPair, pairExps); - updateExps.put(System.identityHashCode(arg), arg); - } - pair.put(System.identityHashCode(pairExps), argType); - } else if (symbol.equals(DataConstraintModel.right)) { - // If the root symbol of the term is right. - List pairExps = new ArrayList<>(); - Expression arg = t.getChildren().get(0); - pairExps.add(arg); // pair - updateExpressionBelonging(expToPair, arg, pairExps); - pairExps.add(null); // left - pairExps.add(t); // right - updateExpressionBelonging(expToPair, t, pairExps); - Type argType = null; - if (arg instanceof Variable) { - argType = ((Variable) arg).getType(); - } else if (arg instanceof Term) { - argType = ((Term) arg).getType(); - } - Type newPairType = DataConstraintModel.typePair; - if (argType == DataConstraintModel.typePair && t.getType() != null) { - List newCompTypeList = new ArrayList<>(); - newCompTypeList.add(null); - newCompTypeList.add(t.getType()); - newPairType = pairTypes.get(newCompTypeList); - if (newPairType == null) { - // Create new tuple type; - newPairType = createNewTupleType(newCompTypeList, DataConstraintModel.typePair); - } - } - if (argType != newPairType && newPairType != null) { - if (arg instanceof Variable) { - ((Variable) arg).setType(newPairType); - argType = newPairType; - } else if (arg instanceof Term) { - ((Term) arg).setType(newPairType); - argType = newPairType; - } - Map updateExps = getUpdateSet(updateFromPair, pairExps); - updateExps.put(System.identityHashCode(arg), arg); - } - pair.put(System.identityHashCode(pairExps), argType); - } else if (symbol.equals(DataConstraintModel.lookup)) { - // If the root symbol of the term is lookup. - List mapExps = new ArrayList<>(); - Expression arg1 = t.getChildren().get(0); // map - mapExps.add(arg1); - updateExpressionBelonging(expToMap, arg1, mapExps); - Expression arg2 = t.getChildren().get(1); // key - mapExps.add(arg2); - updateExpressionBelonging(expToMap, arg2, mapExps); - mapExps.add(t); // value - updateExpressionBelonging(expToMap, t, mapExps); - Type arg1Type = null; - if (arg1 instanceof Variable) { - arg1Type = ((Variable) arg1).getType(); - } else if (arg1 instanceof Term) { - arg1Type = ((Term) arg1).getType(); - } - List newCompTypeList = new ArrayList<>(); - if (arg2 instanceof Variable) { - newCompTypeList.add(((Variable) arg2).getType()); - } else if (arg2 instanceof Term) { - newCompTypeList.add(((Term) arg2).getType()); - } else { - newCompTypeList.add(null); - } - newCompTypeList.add(t.getType()); - if (arg1Type == DataConstraintModel.typeMap || arg1Type == null) { - Type newMapType = mapTypes.get(newCompTypeList); - if (newMapType == null) { - // Create new tuple type; - newMapType = createNewMapType(newCompTypeList, DataConstraintModel.typeMap); - } - // Update the type of the map argument and record the updated expression. - if (arg1 instanceof Variable) { - ((Variable) arg1).setType(newMapType); - arg1Type = newMapType; - } else if (arg1 instanceof Term) { - ((Term) arg1).setType(newMapType); - arg1Type = newMapType; - } - Map updateExps = getUpdateSet(updateFromMap, mapExps); - updateExps.put(System.identityHashCode(arg1), arg1); - } - map.put(System.identityHashCode(mapExps), arg1Type); - } else if (symbol.equals(DataConstraintModel.insert)) { - // If the root symbol of the term is insert. - List mapExps = new ArrayList<>(); - mapExps.add(t); // map - updateExpressionBelonging(expToMap, t, mapExps); - Expression arg1 = t.getChildren().get(1); // key - mapExps.add(arg1); - updateExpressionBelonging(expToMap, arg1, mapExps); - Expression arg2 = t.getChildren().get(2); // value - mapExps.add(arg2); - updateExpressionBelonging(expToMap, arg2, mapExps); - Expression arg0 = t.getChildren().get(0); // map - mapExps.add(arg0); - updateExpressionBelonging(expToMap, arg0, mapExps); - Type termType = t.getType(); - List newCompTypeList = new ArrayList<>(); - if (arg1 instanceof Variable) { - newCompTypeList.add(((Variable) arg1).getType()); - } else if (arg1 instanceof Term) { - newCompTypeList.add(((Term) arg1).getType()); - } else { - newCompTypeList.add(null); - } - if (arg2 instanceof Variable) { - newCompTypeList.add(((Variable) arg2).getType()); - } else if (arg2 instanceof Term) { - newCompTypeList.add(((Term) arg2).getType()); - } else { - newCompTypeList.add(null); - } - Type newTermType = getExpTypeIfUpdatable(termType, mapExps.get(3)); - if (newTermType != null) { - // If the type of the 1st argument of insert is more concrete than the type of the term. - t.setType(newTermType); - termType = newTermType; - Map updateExps = getUpdateSet(updateFromMap, mapExps); - updateExps.put(System.identityHashCode(t), t); - } else { - Type arg3Type = null; - if (mapExps.get(3) != null && mapExps.get(3) instanceof Variable) { - arg3Type = ((Variable) mapExps.get(3)).getType(); - if (compareTypes(arg3Type, t.getType())) { - // If the type of the term is more concrete than the type of the 1st argument of insert. - ((Variable) mapExps.get(3)).setType(t.getType()); - Map updateExps = getUpdateSet(updateFromMap, mapExps); - updateExps.put(System.identityHashCode(mapExps.get(3)), mapExps.get(3)); - } - } else if (mapExps.get(3) != null && mapExps.get(3) instanceof Term) { - arg3Type = ((Term) mapExps.get(3)).getType(); - if (compareTypes(arg3Type, t.getType())) { - // If the type of the term is more concrete than the type of the 1st argument of insert. - ((Term) mapExps.get(3)).setType(t.getType()); - Map updateExps = getUpdateSet(updateFromMap, mapExps); - updateExps.put(System.identityHashCode(mapExps.get(3)), mapExps.get(3)); - } - } - } - if (termType == DataConstraintModel.typeMap || termType == null) { - Type newMapType = mapTypes.get(newCompTypeList); - if (newMapType == null) { - // Create new tuple type; - newMapType = createNewMapType(newCompTypeList, DataConstraintModel.typeMap); - } - // Update the type of the map term and record the updated expression. - t.setType(newMapType); - Map updateExps = getUpdateSet(updateFromMap, mapExps); - updateExps.put(System.identityHashCode(t), t); - if (mapExps.get(3) != null && mapExps.get(3) instanceof Variable) { - ((Variable) mapExps.get(3)).setType(newMapType); - updateExps.put(System.identityHashCode(mapExps.get(3)), mapExps.get(3)); - } else if (mapExps.get(3) != null && mapExps.get(3) instanceof Term) { - ((Term) mapExps.get(3)).setType(newMapType); - updateExps.put(System.identityHashCode(mapExps.get(3)), mapExps.get(3)); - } - termType = newMapType; - } - map.put(System.identityHashCode(mapExps), termType); - } else if (symbol.equals(DataConstraintModel.addMember)) { - // If the root symbol of the term is addMember (addMember(json, key, value)). - List dotExps = new ArrayList<>(); - Expression jsonArg = t.getChildren().get(0); - Expression keyArg = t.getChildren().get(1); - Expression valueArg = t.getChildren().get(2); - dotExps.add(t); // json - updateExpressionBelonging(expToJson, t, dotExps); - dotExps.add(keyArg); // key - updateExpressionBelonging(expToJson, keyArg, dotExps); - dotExps.add(valueArg); // value - updateExpressionBelonging(expToJson, valueArg, dotExps); - dotExps.add(jsonArg); // json - updateExpressionBelonging(expToJson, jsonArg, dotExps); - Type jsonType = t.getType(); - Type valueType = null; - if (valueArg instanceof Variable) { - valueType = ((Variable) valueArg).getType(); - } else if (valueArg instanceof Term) { - valueType = ((Term) valueArg).getType(); - } - String keyName = null; - if (keyArg instanceof Constant) { - keyName = ((Constant) keyArg).getSymbol().getName(); - } - Type jsonArgType = null; - if (jsonArg instanceof Variable) { - jsonArgType = ((Variable) jsonArg).getType(); - } else if (jsonArg instanceof Term) { - jsonArgType = ((Term) jsonArg).getType(); - } - Type newJsonType = DataConstraintModel.typeJson; - if (jsonType == DataConstraintModel.typeJson && jsonArgType != null && keyName != null) { - Map newMemberTypes = new HashMap<>(((JsonType) jsonArgType).getMemberTypes()); - newMemberTypes.put(keyName, valueType); - newJsonType = jsonTypes.get(newMemberTypes); - if (newJsonType == null) { - // Create new json type; - newJsonType = createNewJsonType(newMemberTypes, DataConstraintModel.typeJson); - } - } - if (jsonType != newJsonType && newJsonType != null && !newJsonType.isAncestorOf(jsonType)) { - // Update the type of the json term and record the updated expression. - t.setType(newJsonType); - jsonType = newJsonType; - Map updateExps = getUpdateSet(updateFromJson, dotExps); - updateExps.put(System.identityHashCode(t), t); - } - json.put(System.identityHashCode(dotExps), jsonType); - } else if (symbol.equals(DataConstraintModel.dot)) { - // If the root symbol of the term is dot (json.property). - List dotExps = new ArrayList<>(); - Expression jsonArg = t.getChildren().get(0); - Expression keyArg = t.getChildren().get(1); - dotExps.add(jsonArg); // json - updateExpressionBelonging(expToJson, jsonArg, dotExps); - dotExps.add(keyArg); // key - updateExpressionBelonging(expToJson, keyArg, dotExps); - dotExps.add(t); // value - updateExpressionBelonging(expToJson, t, dotExps); - dotExps.add(null); // json - Type jsonType = null; - if (jsonArg instanceof Variable) { - jsonType = ((Variable) jsonArg).getType(); - } else if (jsonArg instanceof Term) { - jsonType = ((Term) jsonArg).getType(); - } - String keyName = null; - if (keyArg instanceof Constant) { - keyName = ((Constant) keyArg).getSymbol().getName(); - } - Type newJsonType = DataConstraintModel.typeJson; - if (jsonType == DataConstraintModel.typeJson && t.getType() != null && keyName != null) { - Map newMemberTypes = new HashMap<>(); - newMemberTypes.put(keyName, t.getType()); - newJsonType = jsonTypes.get(newMemberTypes); - if (newJsonType == null) { - // Create new json type; - newJsonType = createNewJsonType(newMemberTypes, DataConstraintModel.typeJson); - } - } - if (jsonType != newJsonType && newJsonType != null && !newJsonType.isAncestorOf(jsonType)) { - // Update the type of the json argument and record the updated expression. - if (jsonArg instanceof Variable) { - ((Variable) jsonArg).setType(newJsonType); - jsonType = newJsonType; - } else if (jsonArg instanceof Term) { - ((Term) jsonArg).setType(newJsonType); - jsonType = newJsonType; - } - Map updateExps = getUpdateSet(updateFromJson, dotExps); - updateExps.put(System.identityHashCode(jsonArg), jsonArg); - } - json.put(System.identityHashCode(dotExps), jsonType); - } else if (symbol.equals(DataConstraintModel.dotParam)) { - // If the root symbol of the term is dot (json.{param}). - List dotExps = new ArrayList<>(); - Expression jsonArg = t.getChildren().get(0); - Expression keyArg = t.getChildren().get(1); - dotExps.add(jsonArg); // json (list/map) - updateExpressionBelonging(expToJson, jsonArg, dotExps); - dotExps.add(null); // key - dotExps.add(t); // value - updateExpressionBelonging(expToJson, t, dotExps); - dotExps.add(null); // json - Type jsonType = null; - if (jsonArg instanceof Variable) { - jsonType = ((Variable) jsonArg).getType(); - } else if (jsonArg instanceof Term) { - jsonType = ((Term) jsonArg).getType(); - } - Type keyType = null; - if (keyArg instanceof Variable) { - keyType = ((Variable) keyArg).getType(); - } else if (keyArg instanceof Term) { - keyType = ((Term) keyArg).getType(); - } - Type newJsonType = null; - if (keyType == DataConstraintModel.typeInt) { - newJsonType = DataConstraintModel.typeList; - } else if (keyType == DataConstraintModel.typeString) { - newJsonType = DataConstraintModel.typeMap; - } - if (t.getType() != null) { - if ((jsonType == DataConstraintModel.typeList)) { - newJsonType = listTypes.get(t.getType()); - if (newJsonType == null) { - // Create new list type; - newJsonType = createNewListType(t.getType(), DataConstraintModel.typeList); - } - } else if (jsonType == DataConstraintModel.typeMap) { - List keyValueTypes = Arrays.asList(new Type[] {DataConstraintModel.typeString, t.getType()}); - newJsonType = mapTypes.get(keyValueTypes); - if (newJsonType == null) { - // Create new map type; - newJsonType = createNewMapType(keyValueTypes, DataConstraintModel.typeMap); - } - } - } - if (jsonType != newJsonType && newJsonType != null && !newJsonType.isAncestorOf(jsonType)) { - // Update the type of the json argument and record the updated expression. - if (jsonArg instanceof Variable) { - ((Variable) jsonArg).setType(newJsonType); - jsonType = newJsonType; - } else if (jsonArg instanceof Term) { - ((Term) jsonArg).setType(newJsonType); - jsonType = newJsonType; - } - Map updateExps = getUpdateSet(updateFromJson, dotExps); - updateExps.put(System.identityHashCode(jsonArg), jsonArg); - } - json.put(System.identityHashCode(dotExps), jsonType); - } else if (symbol.equals(DataConstraintModel.cond)) { - // If the root symbol of the term is if function. - Expression c1 = t.getChild(1); - Expression c2 = t.getChild(2); - List condTerms = new ArrayList<>(); - condTerms.add(t); - condTerms.add(c1); - condTerms.add(c2); - expToVariable.put(System.identityHashCode(t), condTerms); - expToVariable.put(System.identityHashCode(c1), condTerms); - expToVariable.put(System.identityHashCode(c2), condTerms); - Type condType = t.getType(); - Map updatedVars = getUpdateSet(updateFromVariable, condTerms); - Type child1Type = getExpTypeIfUpdatable(condType, c1); - if (child1Type != null) { - condType = child1Type; - t.setType(child1Type); - updatedVars.put(System.identityHashCode(t), t); - } else { - if (c1 instanceof Variable && compareTypes(((Variable) c1).getType(), condType)) { - ((Variable) c1).setType(condType); - updatedVars.put(System.identityHashCode(c1), c1); - } else if (c1 instanceof Term && compareTypes(((Term) c1).getType(), condType)) { - ((Term) c1).setType(condType); - updatedVars.put(System.identityHashCode(c1), c1); - } - } - Type child2Type = getExpTypeIfUpdatable(condType, c2); - if (child2Type != null) { - condType = 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(), condType)) { - ((Variable) c2).setType(condType); - updatedVars.put(System.identityHashCode(c2), c2); - } else if (c2 instanceof Term && compareTypes(((Term) c2).getType(), condType)) { - ((Term) c2).setType(condType); - updatedVars.put(System.identityHashCode(c2), c2); - } - } - 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<>(); - consExps.add(t); - expToVariable.put(System.identityHashCode(t), consExps); - Type condType = t.getType(); - Map updatedVars = getUpdateSet(updateFromVariable, consExps); - for (int i = 1; i < symbol.getSignature().length; i++) { - Type tc = symbol.getSignature()[i]; - if (tc == DataConstraintModel.typeList) { - Expression e = t.getChildren().get(i - 1); - Type newType = getExpTypeIfUpdatable(condType, e); - if (newType != null) { - condType = newType; - for (Expression e2 : consExps) { - if (e2 instanceof Variable) { - ((Variable) e2).setType(newType); - updatedVars.put(System.identityHashCode(e2), e2); - } else if (e2 instanceof Term) { - ((Term) e2).setType(newType); - updatedVars.put(System.identityHashCode(e2), e2); - } - } - } else { - if (e instanceof Variable && compareTypes(((Variable) e).getType(), condType)) { - ((Variable) e).setType(condType); - updatedVars.put(System.identityHashCode(e), e); - } else if (e instanceof Term && compareTypes(((Term) e).getType(), condType)) { - ((Term) e).setType(condType); - updatedVars.put(System.identityHashCode(e), e); - } - } - consExps.add(e); - expToVariable.put(System.identityHashCode(e), consExps); - } - } - variables.put(System.identityHashCode(consExps), condType); - } - } - } - for (Channel childCh: ch.getChildren()) { - extractForChannel(childCh); - } - } - }; - extractConstraintsOnExpressionsInTerm.extractForChannel(ch); - - // 1.5 Extract constraints on path parameters and resources. - IExtractConstraintsOnPathParametersAndResources extractConstraintsOnPathParametersAndResources = new IExtractConstraintsOnPathParametersAndResources() { - public void extractForChannel(Channel ch) { - for (ChannelMember cm : ch.getChannelMembers()) { - ResourcePath rPath = cm.getResource(); - while (rPath != null) { - Expression param = rPath.getLastParam(); - if (param != null) { - ResourceHierarchy parent = rPath.getResourceHierarchy().getParent(); - if (parent != null) { - List pathParams = resourcePathParams.get(parent); - if (pathParams == null) { - pathParams = new ArrayList<>(); - resourcePathParams.put(parent, pathParams); - } - pathParams.add(param); - expToPathParams.put(System.identityHashCode(param), pathParams); - Type parentType = parent.getResourceStateType(); - Type paramType = null; - if (param instanceof Variable) { - paramType = ((Variable) param).getType(); - } else if (param instanceof Term) { - paramType = ((Term) param).getType(); - } - if (paramType != null && parentType == null) { - if (paramType.equals(DataConstraintModel.typeString)) { - parentType = DataConstraintModel.typeMap; - } else if (paramType.equals(DataConstraintModel.typeInt)) { - parentType = DataConstraintModel.typeList; - } - if (parentType != null) { - parent.setResourceStateType(parentType); - updateFromResourceOwnership.add(parent); - } - } - } - } - rPath = rPath.getParent(); - } - } - for (Channel childCh: ch.getChildren()) { - extractForChannel(childCh); - } - } - }; - extractConstraintsOnPathParametersAndResources.extractForChannel(ch); - } - - // 1.6 Extract constraints on resource hierarchies. - for (ResourceHierarchy res: model.getResourceHierarchies()) { - if (res.getResourceStateType() != null) { - updateFromResourceOwnership.add(res); - } - } - - // 2. Propagate type information. - while (updateFromResource.size() > 0 || updateFromVariable.size() > 0 || updateFromMessage.size() > 0 - || updateFromConsOrSet.size() > 0 || updateFromTuple.size() > 0 || updateFromPair.size() > 0 - || updateFromMap.size() > 0 || updateFromJson.size() > 0 || updateFromResourceOwnership.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); - updateConsOrSetTypes(resExp, consOrSet, expToConsOrSet, updateFromConsOrSet); - updateTupleTypes(resExp, tuple, expToTuple, updateFromTuple); - updatePairTypes(resExp, pair, expToPair, updateFromPair); - updateMapTypes(resExp, map, expToMap, updateFromMap); - updateJsonTypes(resExp, json, expToJson, updateFromJson); - updateResourcePathParamsTypes(resExp, resourcePathParams, updateFromResourceOwnership); - } - } - 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()) { - Expression var = variableValue.get(i); - updateResourceTypes(var, resources, expToResource, updateFromResource, updateFromResourceOwnership); - updateVaribleTypes(var, variables, expToVariable, updateFromVariable); - updateMessageTypes(var, messages, expToMessage, updateFromMessage); - updateConsOrSetTypes(var, consOrSet, expToConsOrSet, updateFromConsOrSet); - updateTupleTypes(var, tuple, expToTuple, updateFromTuple); - updatePairTypes(var, pair, expToPair, updateFromPair); - updateMapTypes(var, map, expToMap, updateFromMap); - updateJsonTypes(var, json, expToJson, updateFromJson); - updateResourcePathParamsTypes(var, resourcePathParams, updateFromResourceOwnership); - } - } - 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, updateFromResourceOwnership); - updateVaribleTypes(mesExp, variables, expToVariable, updateFromVariable); - updateConsOrSetTypes(mesExp, consOrSet, expToConsOrSet, updateFromConsOrSet); - updateTupleTypes(mesExp, tuple, expToTuple, updateFromTuple); - updatePairTypes(mesExp, pair, expToPair, updateFromPair); - updateMapTypes(mesExp, map, expToMap, updateFromMap); - updateJsonTypes(mesExp, json, expToJson, updateFromJson); - updateResourcePathParamsTypes(mesExp, resourcePathParams, updateFromResourceOwnership); - } - } - if (updateFromConsOrSet.size() > 0) { - Set consKeys = updateFromConsOrSet.keySet(); - Integer consKey = consKeys.iterator().next(); - Map consValue = updateFromConsOrSet.get(consKey); - updateFromConsOrSet.remove(consKey); - for (int i : consValue.keySet()) { - Expression consExp = consValue.get(i); - updateResourceTypes(consExp, resources, expToResource, updateFromResource, updateFromResourceOwnership); - updateVaribleTypes(consExp, variables, expToVariable, updateFromVariable); - updateMessageTypes(consExp, messages, expToMessage, updateFromMessage); - updateConsOrSetTypes(consExp, consOrSet, expToConsOrSet, updateFromConsOrSet); - updateTupleTypes(consExp, tuple, expToTuple, updateFromTuple); - updatePairTypes(consExp, pair, expToPair, updateFromPair); - updateMapTypes(consExp, map, expToMap, updateFromMap); - updateJsonTypes(consExp, json, expToJson, updateFromJson); - } - } - 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, updateFromResourceOwnership); - updateVaribleTypes(tupleExp, variables, expToVariable, updateFromVariable); - updateMessageTypes(tupleExp, messages, expToMessage, updateFromMessage); - updateConsOrSetTypes(tupleExp, consOrSet, expToConsOrSet, updateFromConsOrSet); - updateTupleTypes(tupleExp, tuple, expToTuple, updateFromTuple); - updatePairTypes(tupleExp, pair, expToPair, updateFromPair); - updateMapTypes(tupleExp, map, expToMap, updateFromMap); - updateJsonTypes(tupleExp, json, expToJson, updateFromJson); - } - } - if (updateFromPair.size() > 0) { - Set pairKeys = updateFromPair.keySet(); - Integer pairKey = pairKeys.iterator().next(); - Map pairValue = updateFromPair.get(pairKey); - updateFromPair.remove(pairKey); - for (int i : pairValue.keySet()) { - Expression pairExp = pairValue.get(i); - updateResourceTypes(pairExp, resources, expToResource, updateFromResource, updateFromResourceOwnership); - updateVaribleTypes(pairExp, variables, expToVariable, updateFromVariable); - updateMessageTypes(pairExp, messages, expToMessage, updateFromMessage); - updateConsOrSetTypes(pairExp, consOrSet, expToConsOrSet, updateFromConsOrSet); - updateTupleTypes(pairExp, tuple, expToTuple, updateFromTuple); - updatePairTypes(pairExp, pair, expToPair, updateFromPair); - updateMapTypes(pairExp, map, expToMap, updateFromMap); - updateJsonTypes(pairExp, json, expToJson, updateFromJson); - } - } - if (updateFromMap.size() > 0) { - Set mapKeys = updateFromMap.keySet(); - Integer mapKey = mapKeys.iterator().next(); - Map mapValue = updateFromMap.get(mapKey); - updateFromMap.remove(mapKey); - for (int i : mapValue.keySet()) { - Expression mapExp = mapValue.get(i); - updateResourceTypes(mapExp, resources, expToResource, updateFromResource, updateFromResourceOwnership); - updateVaribleTypes(mapExp, variables, expToVariable, updateFromVariable); - updateMessageTypes(mapExp, messages, expToMessage, updateFromMessage); - updateConsOrSetTypes(mapExp, consOrSet, expToConsOrSet, updateFromConsOrSet); - updateTupleTypes(mapExp, tuple, expToTuple, updateFromTuple); - updatePairTypes(mapExp, pair, expToPair, updateFromPair); - updateMapTypes(mapExp, map, expToMap, updateFromMap); - updateJsonTypes(mapExp, json, expToJson, updateFromJson); - } - } - if (updateFromJson.size() > 0) { - Set jsonKeys = updateFromJson.keySet(); - Integer jsonKey = jsonKeys.iterator().next(); - Map jsonValue = updateFromJson.get(jsonKey); - updateFromJson.remove(jsonKey); - for (int i : jsonValue.keySet()) { - Expression jsonExp = jsonValue.get(i); - updateResourceTypes(jsonExp, resources, expToResource, updateFromResource, updateFromResourceOwnership); - updateVaribleTypes(jsonExp, variables, expToVariable, updateFromVariable); - updateMessageTypes(jsonExp, messages, expToMessage, updateFromMessage); - updateConsOrSetTypes(jsonExp, consOrSet, expToConsOrSet, updateFromConsOrSet); - updateTupleTypes(jsonExp, tuple, expToTuple, updateFromTuple); - updatePairTypes(jsonExp, pair, expToPair, updateFromPair); - updateMapTypes(jsonExp, map, expToMap, updateFromMap); - updateJsonTypes(jsonExp, json, expToJson, updateFromJson); - } - } - if (updateFromResourceOwnership.size() > 0) { - ResourceHierarchy res = updateFromResourceOwnership.iterator().next(); - updateFromResourceOwnership.remove(res); - updateResourceOwnershipTypes(res, resources, expToResource, updateFromResource, updateFromResourceOwnership); - } - } - } - - private static void updateExpressionBelonging(Map>> belonging, Expression exp, List group) { - Set> groups = belonging.get(System.identityHashCode(exp)); - if (groups == null) { - groups = new HashSet<>(); - belonging.put(System.identityHashCode(exp), groups); - groups.add(group); - return; - } - if (!groups.contains(group)) { - groups.add(group); - } - } - - private static void updateResourceTypes(Expression exp, Map> resources, Map> expToResource, - Map> updateFromResource, Set updateFromResourceOwnership) { - List identicalResources = expToResource.get(System.identityHashCode(exp)); - if (identicalResources == null) return; - for (ResourceHierarchy res: resources.keySet()) { - if (resources.get(res) == identicalResources) { - Type resType = res.getResourceStateType(); - Type newResType = getExpTypeIfUpdatable(resType, exp); - if (newResType != null) { - res.setResourceStateType(newResType); - updateFromResourceOwnership.add(res); // To update parent and children resources - // Update identical resources - Map updateExps = getUpdateSet(updateFromResource, identicalResources); - for (Expression resExp : identicalResources) { - 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 updateResourcePathParamsTypes(Expression exp, Map> resourcePathParams, Set updateFromResourceOwnership) { - for (ResourceHierarchy parent: resourcePathParams.keySet()) { - List pathParams = resourcePathParams.get(parent); - if (pathParams.contains(exp)) { - Type parentType = parent.getResourceStateType(); - Type paramType = null; - if (exp instanceof Variable) { - paramType = ((Variable) exp).getType(); - } else if (exp instanceof Term) { - paramType = ((Term) exp).getType(); - } - if (paramType != null && parentType == null) { - if (paramType.equals(DataConstraintModel.typeString)) { - parentType = DataConstraintModel.typeMap; - } else if (paramType.equals(DataConstraintModel.typeInt)) { - parentType = DataConstraintModel.typeList; - } - if (parentType != null) { - parent.setResourceStateType(parentType); - updateFromResourceOwnership.add(parent); - } - } - } - } - } - - private static void updateResourceOwnershipTypes(ResourceHierarchy res, Map> resources, - Map> expToResource, Map> updateFromResource, Set updateFromResourceOwnership) { - for (ResourceHierarchy parent: resources.keySet()) { - Type resType = res.getResourceStateType(); - Set children = parent.getChildren(); - if (res.equals(parent)) { - // Propagate an update of a parent resource type to its children' types. - if (DataConstraintModel.typeList.isAncestorOf(resType)) { - Type newElementType = listComponentTypes.get(resType); - if (newElementType != null && children != null && children.size() == 1) { - ResourceHierarchy element = children.iterator().next(); - Type elementType = element.getResourceStateType(); - if (compareTypes(elementType, newElementType)) { - element.setResourceStateType(newElementType); - updateFromResourceOwnership.add(element); - } - } - } else if (DataConstraintModel.typeMap.isAncestorOf(resType)) { - List newComponentTypes = mapComponentTypes.get(resType); - if (newComponentTypes != null && newComponentTypes.size() == 2 && children != null && children.size() == 1) { - ResourceHierarchy value = children.iterator().next(); - Type valueType = value.getResourceStateType(); - if (compareTypes(valueType, newComponentTypes.get(1))) { - value.setResourceStateType(newComponentTypes.get(1)); - updateFromResourceOwnership.add(value); - } - } - } else if (DataConstraintModel.typeJson.isAncestorOf(resType)) { - Map newMemberTypes = jsonMemberTypes.get(resType); - if (newMemberTypes != null && newMemberTypes.size() > 0 && children != null && children.size() > 0) { - for (ResourceHierarchy chlid: children) { - String key = chlid.getResourceName(); - Type memberType = chlid.getResourceStateType(); - if (compareTypes(memberType, newMemberTypes.get(key))) { - chlid.setResourceStateType(newMemberTypes.get(key)); - updateFromResourceOwnership.add(chlid); - } - } - } - } - } - if (children.contains(res)) { - // Propagate an update of a child resource type to its parent's type. - Type parentType = parent.getResourceStateType(); - if (parentType != null && DataConstraintModel.typeList.isAncestorOf(parentType)) { - Type oldElementType = listComponentTypes.get(parentType); - if (compareTypes(oldElementType, resType)) { - Type newListType = listTypes.get(resType); - if (newListType == null) { - newListType = createNewListType(resType, parentType); - } - if (newListType != null) { - parent.setResourceStateType(newListType); - updateFromResourceOwnership.add(parent); - } - } - } else if (parentType != null && DataConstraintModel.typeMap.isAncestorOf(parentType)) { - List oldComponentTypes = mapComponentTypes.get(parentType); - if (compareTypes(oldComponentTypes.get(1), resType)) { - List newComponentTypes = Arrays.asList(new Type[] {DataConstraintModel.typeString, resType}); - Type newMapType = mapTypes.get(newComponentTypes); - if (newMapType == null) { - newMapType = createNewMapType(newComponentTypes, parentType); - } - if (newMapType != null) { - parent.setResourceStateType(newMapType); - updateFromResourceOwnership.add(parent); - } - } - } else if (parentType != null && DataConstraintModel.typeJson.isAncestorOf(parentType)) { - Map oldMemberTypes = jsonMemberTypes.get(parentType); - String key= res.getResourceName(); - if (oldMemberTypes == null || compareTypes(oldMemberTypes.get(key), resType)) { - Map newMemberTypes = new HashMap<>(); - if (oldMemberTypes != null) newMemberTypes.putAll(oldMemberTypes); - newMemberTypes.put(key, resType); - Type newJsonType = jsonTypes.get(newMemberTypes); - if (newJsonType == null) { - newJsonType = createNewJsonType(newMemberTypes, parentType); - } - if (newJsonType != null) { - parent.setResourceStateType(newJsonType); - updateFromResourceOwnership.add(parent); - } - } - } - } - } - // Propagate an update of the resource to its expressions. - List identicalResources = resources.get(res); - if (identicalResources != null) { - Type newResType = res.getResourceStateType(); - for (Expression resExp: identicalResources) { - Type resType = null; - if (resExp instanceof Variable) { - resType = ((Variable) resExp).getType(); - } else if (resExp instanceof Term) { - resType = ((Term) resExp).getType(); - } - if (resType == null || compareTypes(resType, newResType)) { - Map updateExps = getUpdateSet(updateFromResource, identicalResources); - 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 updateVaribleTypes(Expression exp, Map variables, - Map> expToVariable, Map> updateFromVariable) { - List sameVariable = expToVariable.get(System.identityHashCode(exp)); - 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 (Expression v : sameVariable) { - if (v != exp) { - if (v instanceof Variable) { - ((Variable) v).setType(newVarType); - updateVars.put(System.identityHashCode(v), v); - } else if (v instanceof Term) { - ((Term) v).setType(newVarType); - updateVars.put(System.identityHashCode(v), v); - } - } - } - } else { - Map updateVars = getUpdateSet(updateFromVariable, sameVariable); - for (Expression v : sameVariable) { - if (v instanceof Variable) { - Type orgVarType = ((Variable) v).getType(); - if (orgVarType != varType && compareTypes(orgVarType, varType)) { - ((Variable) v).setType(varType); - updateVars.put(System.identityHashCode(v), v); - } - } else if (v instanceof Term) { - Type orgVarType = ((Term) v).getType(); - if (orgVarType != varType && compareTypes(orgVarType, varType)) { - ((Term) v).setType(varType); - updateVars.put(System.identityHashCode(v), v); - } - } - } - } - } - - 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 (Channel 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 updateConsOrSetTypes(Expression exp, Map consOrSet, - Map>> expToConsOrSet, Map> updateFromConsOrSet) { - Set> consComponentGroups = expToConsOrSet.get(System.identityHashCode(exp)); - if (consComponentGroups == null) return; - for (List consOrSetComponentGroup: consComponentGroups) { - int idx = consOrSetComponentGroup.indexOf(exp); - switch (idx) { - case 0: - // exp is a list itself. - if (!(exp instanceof Term)) break; - Type listType = consOrSet.get(System.identityHashCode(consOrSetComponentGroup)); - Type expType = getExpTypeIfUpdatable(listType, exp); - if (expType != null) { - consOrSet.put(System.identityHashCode(consOrSetComponentGroup), expType); - Map updateExps = getUpdateSet(updateFromConsOrSet, consOrSetComponentGroup); - if (consOrSetComponentGroup.get(2) instanceof Variable) { - ((Variable) consOrSetComponentGroup.get(2)).setType(expType); - updateExps.put(System.identityHashCode(consOrSetComponentGroup.get(2)), consOrSetComponentGroup.get(2)); - } else if (consOrSetComponentGroup.get(2) instanceof Term) { - ((Term) consOrSetComponentGroup.get(2)).setType(expType); - updateExps.put(System.identityHashCode(consOrSetComponentGroup.get(2)), consOrSetComponentGroup.get(2)); - } - Type compType = listComponentTypes.get(expType); - if (consOrSetComponentGroup.get(1) != null && consOrSetComponentGroup.get(1) instanceof Variable) { - ((Variable) consOrSetComponentGroup.get(1)).setType(compType); - updateExps.put(System.identityHashCode(consOrSetComponentGroup.get(1)), consOrSetComponentGroup.get(1)); - } else if (consOrSetComponentGroup.get(1) != null && consOrSetComponentGroup.get(1) instanceof Term) { - ((Term) consOrSetComponentGroup.get(1)).setType(compType); - updateExps.put(System.identityHashCode(consOrSetComponentGroup.get(1)), consOrSetComponentGroup.get(1)); - } - } - break; - case 1: - // exp is a list's component. - listType = consOrSet.get(System.identityHashCode(consOrSetComponentGroup)); - 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); - } - consOrSet.put(System.identityHashCode(consOrSetComponentGroup), newListType); - Map updateExps = getUpdateSet(updateFromConsOrSet, consOrSetComponentGroup); - if (consOrSetComponentGroup.get(0) instanceof Term) { - ((Term) consOrSetComponentGroup.get(0)).setType(newListType); - updateExps.put(System.identityHashCode(consOrSetComponentGroup.get(0)), consOrSetComponentGroup.get(0)); - } - if (consOrSetComponentGroup.get(2) instanceof Variable) { - ((Variable) consOrSetComponentGroup.get(2)).setType(newListType); - updateExps.put(System.identityHashCode(consOrSetComponentGroup.get(2)), consOrSetComponentGroup.get(2)); - } else if (consOrSetComponentGroup.get(2) instanceof Term) { - ((Term) consOrSetComponentGroup.get(2)).setType(newListType); - updateExps.put(System.identityHashCode(consOrSetComponentGroup.get(2)), consOrSetComponentGroup.get(2)); - } - } - break; - case 2: - // exp is a list itself. - listType = consOrSet.get(System.identityHashCode(consOrSetComponentGroup)); - expType = getExpTypeIfUpdatable(listType, exp); - if (expType != null) { - consOrSet.put(System.identityHashCode(consOrSetComponentGroup), expType); - Map updateExps = getUpdateSet(updateFromConsOrSet, consOrSetComponentGroup); - if (consOrSetComponentGroup.get(0) instanceof Term) { - ((Term) consOrSetComponentGroup.get(0)).setType(expType); - updateExps.put(System.identityHashCode(consOrSetComponentGroup.get(0)), consOrSetComponentGroup.get(0)); - } - compType = listComponentTypes.get(expType); - if (consOrSetComponentGroup.get(1) != null && consOrSetComponentGroup.get(1) instanceof Variable) { - ((Variable) consOrSetComponentGroup.get(1)).setType(compType); - updateExps.put(System.identityHashCode(consOrSetComponentGroup.get(1)), consOrSetComponentGroup.get(1)); - } else if (consOrSetComponentGroup.get(1) != null && consOrSetComponentGroup.get(1) instanceof Term) { - ((Term) consOrSetComponentGroup.get(1)).setType(compType); - updateExps.put(System.identityHashCode(consOrSetComponentGroup.get(1)), consOrSetComponentGroup.get(1)); - } - } - } - } - } - - private static void updateTupleTypes(Expression exp, Map tuple, - Map>> expToTuple, Map> updateFromTuple) { - Set> tupleComponentGroups = expToTuple.get(System.identityHashCode(exp)); - if (tupleComponentGroups == null) return; - for (List tupleComponentGroup: tupleComponentGroups) { - int idx = tupleComponentGroup.indexOf(exp); - if (idx == 0) { - // exp is a tuple itself. - Type tupleType = tuple.get(System.identityHashCode(tupleComponentGroup)); - Type newTupleType = getExpTypeIfUpdatable(tupleType, exp); - if (newTupleType != null) { - // Propagate an update of a tuple's type to its components' types. - tuple.put(System.identityHashCode(tupleComponentGroup), newTupleType); - List componentTypes = tupleComponentTypes.get(newTupleType); - Map updateExps = getUpdateSet(updateFromTuple, tupleComponentGroup); - for (int i = 1; i < tupleComponentGroup.size(); i++) { - Expression compExp = tupleComponentGroup.get(i); - if (compExp instanceof Variable) { - Type compType = ((Variable) compExp).getType(); - if (compType != null && DataConstraintModel.typeTuple.isAncestorOf(compType)) { - // If the type of one component (compExp) is also tuple. - Type newExpType = tupleTypes.get(componentTypes.subList(i - 1, componentTypes.size())); - if (newExpType == null) { - // Create new tuple type; - newExpType = createNewTupleType(componentTypes.subList(i - 1, componentTypes.size()), compType); - } - if (compareTypes(compType, newExpType)) { - ((Variable) compExp).setType(newExpType); - updateExps.put(System.identityHashCode(compExp), compExp); - } - } else { - if (i - 1 < componentTypes.size()) { - if (compareTypes(compType, componentTypes.get(i - 1))) { - ((Variable) compExp).setType(componentTypes.get(i - 1)); - updateExps.put(System.identityHashCode(compExp), compExp); - } - } else { - // for insert - if (compareTypes(compType, newTupleType)) { - ((Variable) compExp).setType(newTupleType); - updateExps.put(System.identityHashCode(compExp), compExp); - } - } - } - } else if (compExp instanceof Term) { - Type compType = ((Term) compExp).getType(); - if (compType != null && DataConstraintModel.typeTuple.isAncestorOf(compType)) { - // If the type of one component (compExp) is also tuple. - Type newExpType = tupleTypes.get(componentTypes.subList(i - 1, componentTypes.size())); - if (newExpType == null) { - // Create new tuple type; - newExpType = createNewTupleType(componentTypes.subList(i - 1, componentTypes.size()), compType); - } - if (compareTypes(compType, newExpType)) { - ((Term) compExp).setType(newExpType); - updateExps.put(System.identityHashCode(compExp), compExp); - } - } else { - if (i - 1 < componentTypes.size()) { - if (compareTypes(compType, componentTypes.get(i - 1))) { - ((Term) compExp).setType(componentTypes.get(i - 1)); - updateExps.put(System.identityHashCode(compExp), compExp); - } - } else { - // for insert - if (compareTypes(compType, newTupleType)) { - ((Term) compExp).setType(newTupleType); - updateExps.put(System.identityHashCode(compExp), compExp); - } - } - } - } - } - } - } else { - // exp is a tuple's component. - Type tupleType = tuple.get(System.identityHashCode(tupleComponentGroup)); - List componentTypes = tupleComponentTypes.get(tupleType); - boolean updated = false; - if (idx == 1) { - Type compType = componentTypes.get(idx - 1); - Type newCompType = getExpTypeIfUpdatable(compType, exp); - if (newCompType != null) { - componentTypes = new ArrayList<>(componentTypes); - componentTypes.set(idx - 1, newCompType); - updated = true; - } - } else { - Type expType = null; - if (exp instanceof Term) { - expType = ((Term) exp).getType(); - } else if (exp instanceof Variable) { - expType = ((Variable) exp).getType(); - } - if (expType != null && DataConstraintModel.typeTuple.isAncestorOf(expType)) { - // If the type of the updated component (exp) is also tuple. - List subCompTypes = tupleComponentTypes.get(expType); - componentTypes = new ArrayList<>(componentTypes); - for (int i = 0; i < subCompTypes.size(); i++) { - if (componentTypes.size() < i + 2) { - componentTypes.add(subCompTypes.get(i)); - updated = true; - } else if (compareTypes(componentTypes.get(i + 1), subCompTypes.get(i))) { - componentTypes.set(i + 1, subCompTypes.get(i)); - updated = true; - } - } - } else { - Type compType = componentTypes.get(idx - 1); - Type newCompType = getExpTypeIfUpdatable(compType, exp); - if (newCompType != null) { - componentTypes = new ArrayList<>(componentTypes); - componentTypes.set(idx - 1, newCompType); - updated = true; - } - } - } - if (updated) { - // Propagate an update of a component's type to its container's (tuple's) type. - Type newTupleType = tupleTypes.get(componentTypes); - if (newTupleType == null) { - // Create new tuple type; - newTupleType = createNewTupleType(componentTypes, tupleType); - } - Map updateExps = getUpdateSet(updateFromTuple, tupleComponentGroup); - Expression tupleExp = tupleComponentGroup.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(tupleComponentGroup), newTupleType); - } - } - } - } - - private static void updatePairTypes(Expression exp, Map pair, - Map>> expToPair, Map> updateFromPair) { - Set> pairComponentGroups = expToPair.get(System.identityHashCode(exp)); - if (pairComponentGroups == null) return; - for (List pairComponentGroup: pairComponentGroups) { - int idx = pairComponentGroup.indexOf(exp); - if (idx == 0) { - // exp is a pair itself. - Type pairType = pair.get(System.identityHashCode(pairComponentGroup)); - Type newPairType = getExpTypeIfUpdatable(pairType, exp); - if (newPairType != null) { - // Propagate an update of a pair's type to its components' types. - pair.put(System.identityHashCode(pairComponentGroup), newPairType); - Type componentType = pairComponentTypes.get(newPairType); - Map updateExps = getUpdateSet(updateFromPair, pairComponentGroup); - for (int i = 1; i < pairComponentGroup.size(); i++) { - Expression compExp = pairComponentGroup.get(i); - if (compExp instanceof Variable) { - if (compareTypes(((Variable) compExp).getType(), componentType)) { - ((Variable) compExp).setType(componentType); - updateExps.put(System.identityHashCode(compExp), compExp); - } - } else if (compExp instanceof Term) { - if (compareTypes(((Term) compExp).getType(), componentType)) { - ((Term) compExp).setType(componentType); - updateExps.put(System.identityHashCode(compExp), compExp); - } - } - } - } - } else { - // exp is a pair's component. - Type pairType = pair.get(System.identityHashCode(pairComponentGroup)); - Type compType = pairComponentTypes.get(pairType); - Type newCompType = getExpTypeIfUpdatable(compType, exp); - if (newCompType != null) { - // Propagate an update of a component's type to its container's (pair's) type. - Type newPairType = pairTypes.get(compType); - if (newPairType != null) { - Map updateExps = getUpdateSet(updateFromPair, pairComponentGroup); - Expression pairExp = pairComponentGroup.get(0); - if (pairExp instanceof Variable) { - ((Variable) pairExp).setType(newPairType); - updateExps.put(System.identityHashCode(pairExp), pairExp); - } else if (pairExp instanceof Term) { - ((Term) pairExp).setType(newPairType); - updateExps.put(System.identityHashCode(pairExp), pairExp); - } - pair.put(System.identityHashCode(pairComponentGroup), newPairType); - } - } - } - } - } - - private static void updateMapTypes(Expression exp, Map map, - Map>> expToMap, Map> updateFromMap) { - Set> mapComponentGroups = expToMap.get(System.identityHashCode(exp)); - if (mapComponentGroups == null) return; - for (List mapComponentGroup: mapComponentGroups) { - int idx = mapComponentGroup.indexOf(exp); - if (idx == 0 || idx == 3) { - // exp is a map itself. - Type mapType = map.get(System.identityHashCode(mapComponentGroup)); - Type newMapType = getExpTypeIfUpdatable(mapType, exp); - if (newMapType != null) { - // Propagate an update of a map's type to its components' types. - map.put(System.identityHashCode(mapComponentGroup), newMapType); - List componentTypes = mapComponentTypes.get(newMapType); - Map updateExps = getUpdateSet(updateFromMap, mapComponentGroup); - for (int i = 1; i < mapComponentGroup.size() && i < 3; i++) { - Expression compExp = mapComponentGroup.get(i); - if (compExp instanceof Variable) { - 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 - 1))) { - ((Term) compExp).setType(componentTypes.get(i - 1)); - updateExps.put(System.identityHashCode(compExp), compExp); - } - } - } - // Propagate an update of a map's type to another map's type. - Expression compExp = null; - if (idx == 0 && mapComponentGroup.size() == 4) { // for insert - compExp = mapComponentGroup.get(3); - } else if (idx == 3) { - compExp = mapComponentGroup.get(0); - } - if (compExp != null) { - if (compExp instanceof Variable) { - if (compareTypes(((Variable) compExp).getType(), newMapType)) { - ((Variable) compExp).setType(newMapType); - updateExps.put(System.identityHashCode(compExp), compExp); - } - } else if (compExp instanceof Term) { - if (compareTypes(((Term) compExp).getType(), newMapType)) { - ((Term) compExp).setType(newMapType); - updateExps.put(System.identityHashCode(compExp), compExp); - } - } - } - } - } else { - // exp is a map's key or value. - Type mapType = map.get(System.identityHashCode(mapComponentGroup)); - List componentTypes = mapComponentTypes.get(mapType); - 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 (map's) type. - componentTypes = new ArrayList<>(componentTypes); - componentTypes.set(idx - 1, newCompType); - Type newMapType = mapTypes.get(componentTypes); - if (newMapType == null) { - // Create new map type; - newMapType = createNewMapType(componentTypes, mapType); - } - Map updateExps = getUpdateSet(updateFromMap, mapComponentGroup); - Expression mapExp = mapComponentGroup.get(0); - if (mapExp instanceof Variable) { - ((Variable) mapExp).setType(newMapType); - updateExps.put(System.identityHashCode(mapExp), mapExp); - } else if (mapExp instanceof Term) { - ((Term) mapExp).setType(newMapType); - updateExps.put(System.identityHashCode(mapExp), mapExp); - } - if (mapComponentGroup.size() == 4) { // for insert - mapExp = mapComponentGroup.get(3); - if (mapExp instanceof Variable) { - ((Variable) mapExp).setType(newMapType); - updateExps.put(System.identityHashCode(mapExp), mapExp); - } else if (mapExp instanceof Term) { - ((Term) mapExp).setType(newMapType); - updateExps.put(System.identityHashCode(mapExp), mapExp); - } - } - map.put(System.identityHashCode(mapComponentGroup), newMapType); - } - } - } - } - - - private static void updateJsonTypes(Expression exp, Map json, - Map>> expToJson, Map> updateFromJson) { - Set> jsonMemberGroups = expToJson.get(System.identityHashCode(exp)); - if (jsonMemberGroups == null) return; - for (List jsonMemberGroup: jsonMemberGroups) { - int idx = jsonMemberGroup.indexOf(exp); - if (idx == 3) { - // exp is a json argument (0:t = addMember(3:json, 1:key, 2:value)). - Type jsonType = json.get(System.identityHashCode(jsonMemberGroup)); - if (jsonType != null && jsonMemberTypes.get(jsonType) != null) { - Map memberTypes = new HashMap<>(jsonMemberTypes.get(jsonType)); - Map argMemberTypes = new HashMap<>(memberTypes); - String keyName = null; - Type valueType = null; - if (jsonMemberGroup.get(1) instanceof Constant) { - keyName = ((Constant) jsonMemberGroup.get(1)).getSymbol().getName(); - valueType = ((Constant) jsonMemberGroup.get(1)).getType(); - argMemberTypes.remove(keyName); - } - Type jsonArgType = jsonTypes.get(argMemberTypes); - Type newJsonArgType = getExpTypeIfUpdatable(jsonArgType, exp); - if (newJsonArgType != null && keyName != null) { - // Propagate an update of a json arg's type to its container's (json's) type. - argMemberTypes = ((JsonType) newJsonArgType).getMemberTypes(); - argMemberTypes.put(keyName, valueType); - memberTypes.putAll(argMemberTypes); - Type newJsonType = jsonTypes.get(memberTypes); - if (newJsonType == null) { - // Create new json type. - newJsonType = createNewJsonType(memberTypes, jsonType); - } - // Update the type of the json term and record the updated expression. - Map updateExps = getUpdateSet(updateFromJson, jsonMemberGroup); - Expression jsonExp = jsonMemberGroup.get(0); - if (jsonExp instanceof Variable) { - ((Variable) jsonExp).setType(newJsonType); - updateExps.put(System.identityHashCode(jsonExp), jsonExp); - } else if (jsonExp instanceof Term) { - ((Term) jsonExp).setType(newJsonType); - updateExps.put(System.identityHashCode(jsonExp), jsonExp); - } - json.put(System.identityHashCode(jsonMemberGroup), newJsonType); - } - } - } else if (idx == 2) { - // exp is a value (0:t = addMember(3:json, 1:key, 2:value) or 2:value = dot(0:list/map, 1:key)). - Type jsonType = json.get(System.identityHashCode(jsonMemberGroup)); - Type newJsonType = null; - if (exp instanceof Term && ((Term) exp).getSymbol().equals(DataConstraintModel.dotParam)) { - if (DataConstraintModel.typeList.isAncestorOf(jsonType)) { - Type elementType = listComponentTypes.get(jsonType); - Type newElementType = getExpTypeIfUpdatable(elementType, exp); - if (newElementType != null) { - // Propagate an update of a member's type to its container's (json's) type. - newJsonType = listTypes.get(newElementType); - if (newJsonType == null) { - // Create new json type. - newJsonType = createNewListType(newElementType, jsonType); - } - } - } else if (DataConstraintModel.typeMap.isAncestorOf(jsonType)) { - List keyValueTypes = mapComponentTypes.get(jsonType); - Type newValueType = getExpTypeIfUpdatable(keyValueTypes.get(1), exp); - if (newValueType != null) { - // Propagate an update of a member's type to its container's (json's) type. - List newKeyValueTypes = Arrays.asList(new Type[] {DataConstraintModel.typeString, newValueType}); - newJsonType = mapTypes.get(newKeyValueTypes); - if (newJsonType == null) { - // Create new json type. - newJsonType = createNewMapType(newKeyValueTypes, jsonType); - } - } - } - } else { - Map memberTypes = jsonMemberTypes.get(jsonType); - String keyName = null; - if (jsonMemberGroup.get(1) instanceof Constant) { - keyName = ((Constant) jsonMemberGroup.get(1)).getSymbol().getName(); - } - if (memberTypes != null) { - Type memberType = memberTypes.get(keyName); - Type newMemberType = getExpTypeIfUpdatable(memberType, exp); - if (newMemberType != null && keyName != null) { - // Propagate an update of a member's type to its container's (json's) type. - Map newMemberTypes = new HashMap<>(memberTypes); - newMemberTypes.put(keyName, newMemberType); - newJsonType = jsonTypes.get(newMemberTypes); - if (newJsonType == null) { - // Create new json type. - newJsonType = createNewJsonType(newMemberTypes, jsonType); - } - } - } - } - if (newJsonType != null) { - // Update the type of the json term and record the updated expression. - Map updateExps = getUpdateSet(updateFromJson, jsonMemberGroup); - Expression jsonExp = jsonMemberGroup.get(0); - if (jsonExp instanceof Variable) { - ((Variable) jsonExp).setType(newJsonType); - updateExps.put(System.identityHashCode(jsonExp), jsonExp); - } else if (jsonExp instanceof Term) { - ((Term) jsonExp).setType(newJsonType); - updateExps.put(System.identityHashCode(jsonExp), jsonExp); - } - json.put(System.identityHashCode(jsonMemberGroup), newJsonType); - } - } - } - } - - private static Type createNewListType(Type compType, Type parentType) { - String compTypeName = getInterfaceTypeName(compType); - List childrenTypes = getChildrenTypes(parentType, listComponentTypes.keySet()); - 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 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))); - } - List childrenTypes = getChildrenTypes(parentTupleType, tupleComponentTypes.keySet()); - 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 Type createNewMapType(List componentTypes, Type parentMapType) { - String implTypeName = "HashMap<>"; - String interfaceTypeName = "Map<$x, $y>"; - if (componentTypes.size() == 2) { - implTypeName = implTypeName.replace("$x", getImplementationTypeName(componentTypes.get(0))); - interfaceTypeName = interfaceTypeName.replace("$x", getInterfaceTypeName(componentTypes.get(0))); - implTypeName = implTypeName.replace("$y", getImplementationTypeName(componentTypes.get(1))); - interfaceTypeName = interfaceTypeName.replace("$y", getInterfaceTypeName(componentTypes.get(1))); - } - List childrenTypes = getChildrenTypes(parentMapType, mapComponentTypes.keySet()); - Type newMapType = new Type("Map", implTypeName, interfaceTypeName, parentMapType); - mapTypes.put(componentTypes, newMapType); - mapComponentTypes.put(newMapType, componentTypes); - for (Type childType : childrenTypes) { - if (compareTypes(childType, newMapType)) { - if (newMapType.getParentTypes().contains(parentMapType)) { - newMapType.replaceParentType(parentMapType, childType); - } else { - newMapType.addParentType(childType); - } - } else if (compareTypes(newMapType, childType)) { - childType.replaceParentType(parentMapType, newMapType); - } - } - return newMapType; - } - - private static JsonType createNewJsonType(Map memberTypes, Type parentJsonType) { - String implTypeName = "HashMap<>"; - String interfaceTypeName = "Map"; - List childrenTypes = getChildrenTypes(parentJsonType, jsonMemberTypes.keySet()); - JsonType newJsonType = new JsonType("Json", implTypeName, interfaceTypeName, parentJsonType); - for (String key: memberTypes.keySet()) { - newJsonType.addMemberType(key, memberTypes.get(key)); - } - jsonTypes.put(memberTypes, newJsonType); - jsonMemberTypes.put(newJsonType, memberTypes); - for (Type childType : childrenTypes) { - if (compareTypes(childType, newJsonType)) { - if (newJsonType.getParentTypes().contains(parentJsonType)) { - newJsonType.replaceParentType(parentJsonType, childType); - } else { - newJsonType.addParentType(childType); - } - } else if (compareTypes(newJsonType, childType)) { - childType.replaceParentType(parentJsonType, newJsonType); - } - } - return newJsonType; - } - - /** - * Get children types of a given type from given set of types. - * @param parentType a type - * @param allTypes set of types - * @return list of the children types - */ - private static List getChildrenTypes(Type parentType, Set allTypes) { - List childrenTypes = new ArrayList<>(); - for (Type childType : allTypes) { - if (childType.getParentTypes().contains(parentType)) { - childrenTypes.add(childType); - } - } - return childrenTypes; - } - - private static String getImplementationTypeName(Type type) { - if (type == null) - return "Object"; - String wrapperType = DataConstraintModel.getWrapperType(type); - if (wrapperType != null) - return wrapperType; - return type.getImplementationTypeName(); - } - - private static String getInterfaceTypeName(Type type) { - if (type == null) - return "Object"; - String wrapperType = DataConstraintModel.getWrapperType(type); - if (wrapperType != null) - return wrapperType; - return type.getInterfaceTypeName(); - } - - 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; - } - - /** - * 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) return true; - if (originalType != newType && newType != null) { - if (originalType.isAncestorOf(newType)) return true; - if (newType.isAncestorOf(originalType)) return false; - if (DataConstraintModel.typeMap.isAncestorOf(originalType) - && DataConstraintModel.typeMap.isAncestorOf(newType)) { - List originalCompTypes = mapComponentTypes.get(originalType); - List newCompTypes = mapComponentTypes.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.typeTuple.isAncestorOf(originalType) - && DataConstraintModel.typeTuple.isAncestorOf(newType)) { - List originalCompTypes = tupleComponentTypes.get(originalType); - List newCompTypes = tupleComponentTypes.get(newType); - if (originalCompTypes == null) return true; - originalCompTypes = new ArrayList<>(originalCompTypes); - newCompTypes = new ArrayList<>(newCompTypes); - for (int i = 0; i < originalCompTypes.size(); i++) { - if (originalCompTypes.get(i) != null) { - if (DataConstraintModel.typeTuple.isAncestorOf(originalCompTypes.get(i))) { - // Unfold the nested tuple's types. - Type tupleType = originalCompTypes.remove(i); - for (Type t: tupleComponentTypes.get(tupleType)) { - originalCompTypes.add(t); - } - } - if (newCompTypes.size() - 1 < i) return false; - if (newCompTypes.get(i) != null && DataConstraintModel.typeTuple.isAncestorOf(newCompTypes.get(i))) { - // Unfold the nested tuple's types. - Type tupleType = newCompTypes.remove(i); - for (Type t: tupleComponentTypes.get(tupleType)) { - newCompTypes.add(t); - } - } - if (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; - } - if (DataConstraintModel.typeJson.isAncestorOf(originalType) && DataConstraintModel.typeJson.isAncestorOf(newType)) { - Map originalMemberTypes = jsonMemberTypes.get(originalType); - Map newMemberTypes = jsonMemberTypes.get(newType); - if (originalMemberTypes == null) return true; - if (originalMemberTypes.keySet().size() < newMemberTypes.keySet().size() - && newMemberTypes.keySet().containsAll(originalMemberTypes.keySet())) return true; - if (originalMemberTypes.keySet().size() > newMemberTypes.keySet().size()) return false; - if (!newMemberTypes.keySet().containsAll(originalMemberTypes.keySet())) return false; - for (String key: originalMemberTypes.keySet()) { - if (!originalMemberTypes.get(key).isAncestorOf(newMemberTypes.get(key))) return false; - } - return true; - } - } - return false; - } - - private static interface IGroupExpressionsByResource { - public void groupForChannel(Channel ch); - } - - private static interface IGroupExpressionsByVariable { - public void groupForChannel(Channel ch); - } - - private static interface IGroupExpressionsByMessage { - public void groupForChannel(Channel rootCh, Channel ch); - } - - private static interface IExtractConstraintsOnExpressionsInTerm { - public void extractForChannel(Channel ch); - } - - private static interface IExtractConstraintsOnPathParametersAndResources { - public void extractForChannel(Channel ch); - } -} diff --git a/AlgebraicDataflowArchitectureModel/src/application/actions/JavaPrototypeGenerateAction.java b/AlgebraicDataflowArchitectureModel/src/application/actions/JavaPrototypeGenerateAction.java index 846c273..adfd094 100644 --- a/AlgebraicDataflowArchitectureModel/src/application/actions/JavaPrototypeGenerateAction.java +++ b/AlgebraicDataflowArchitectureModel/src/application/actions/JavaPrototypeGenerateAction.java @@ -15,10 +15,12 @@ import code.ast.*; import generators.CodeGeneratorFromDataFlowGraph; import generators.DataTransferMethodAnalyzer; +import generators.ILanguageSpecific; import generators.JavaCodeGenerator; import generators.JavaMethodBodyGenerator; import generators.JavaSpecific; import generators.StandaloneSpecific; +import generators.TypeInference; import models.dataConstraintModel.ResourceHierarchy; import models.dataConstraintModel.ResourcePath; import models.dataFlowModel.DataTransferModel; @@ -41,9 +43,11 @@ public void actionPerformed(ActionEvent e) { DataFlowGraph graph = editor.getDataFlowGraph(); if (graph != null) { + ILanguageSpecific langSpec = new JavaSpecific(); DataTransferModel model = editor.getModel(); ModelExtension.extendModel(model); - TypeInference.infer(model); + TypeInference typeInference = new TypeInference(langSpec); + typeInference.infer(model); DataTransferMethodAnalyzer.decideToStoreResourceStates(graph); String fileName = editor.getCurFileName(); if (fileName == null) fileName = "Main"; @@ -61,7 +65,7 @@ JavaCodeGenerator.resetMainTypeName(); // use the default main type's name. } // editor.setCodes(JavaMethodBodyGenerator.doGenerate(graph, model, JavaCodeGenerator.doGenerate(graph, model))); - editor.setCodes(new CodeGeneratorFromDataFlowGraph().generateCode(model, graph, new StandaloneSpecific(), new JavaSpecific())); + editor.setCodes(new CodeGeneratorFromDataFlowGraph().generateCode(model, graph, new StandaloneSpecific(), langSpec)); ModelExtension.recoverModel(model); for (CompilationUnit file : editor.getCodes()) { System.out.println(file); diff --git a/AlgebraicDataflowArchitectureModel/src/application/actions/JerseyPrototypeGenerateAction.java b/AlgebraicDataflowArchitectureModel/src/application/actions/JerseyPrototypeGenerateAction.java index da1a3df..1b64345 100644 --- a/AlgebraicDataflowArchitectureModel/src/application/actions/JerseyPrototypeGenerateAction.java +++ b/AlgebraicDataflowArchitectureModel/src/application/actions/JerseyPrototypeGenerateAction.java @@ -13,10 +13,12 @@ import code.ast.*; import generators.CodeGeneratorFromDataFlowGraph; import generators.DataTransferMethodAnalyzer; +import generators.ILanguageSpecific; import generators.JavaSpecific; import generators.JerseyCodeGenerator; import generators.JerseyMethodBodyGenerator; import generators.JerseySpecific; +import generators.TypeInference; import models.dataConstraintModel.ResourceHierarchy; import models.dataFlowModel.DataTransferModel; import models.dataFlowModel.ModelExtension; @@ -38,9 +40,11 @@ public void actionPerformed(ActionEvent e) { DataFlowGraph graph = editor.getDataFlowGraph(); if (graph != null) { + ILanguageSpecific langSpec = new JavaSpecific(); DataTransferModel model = editor.getModel(); ModelExtension.extendModel(model); - TypeInference.infer(model); + TypeInference typeInference = new TypeInference(langSpec); + typeInference.infer(model); DataTransferMethodAnalyzer.decideToStoreResourceStates(graph); String fileName = editor.getCurFileName(); if (fileName == null) fileName = "Main"; @@ -58,7 +62,7 @@ JerseyCodeGenerator.resetMainTypeName(); // use the default main type's name. } // editor.setCodes(JerseyMethodBodyGenerator.doGenerate(graph, model, JerseyCodeGenerator.doGenerate(graph, model))); - editor.setCodes(new CodeGeneratorFromDataFlowGraph().generateCode(model, graph, new JerseySpecific(), new JavaSpecific())); + editor.setCodes(new CodeGeneratorFromDataFlowGraph().generateCode(model, graph, new JerseySpecific(), langSpec)); ModelExtension.recoverModel(model); for (CompilationUnit file : editor.getCodes()) { System.out.println(file); diff --git a/AlgebraicDataflowArchitectureModel/src/application/simulator/SimulatorWindow.java b/AlgebraicDataflowArchitectureModel/src/application/simulator/SimulatorWindow.java index 5470a65..3ba4fe5 100644 --- a/AlgebraicDataflowArchitectureModel/src/application/simulator/SimulatorWindow.java +++ b/AlgebraicDataflowArchitectureModel/src/application/simulator/SimulatorWindow.java @@ -1,7 +1,9 @@ package application.simulator; -import algorithms.TypeInference; import application.editor.Editor; +import generators.JavaSpecific; +import generators.TypeInference; + import com.mxgraph.model.mxCell; import com.mxgraph.model.mxGeometry; import com.mxgraph.model.mxGraphModel; @@ -89,7 +91,8 @@ setVisible(true); DataTransferModel model = this.editor.getModel(); - TypeInference.infer(model); + TypeInference typeInference = new TypeInference(new JavaSpecific()); + typeInference.infer(model); simulator = new Simulator(model); SimulationLayout layout = new SimulationLayout(simulator.getCurState()); layout.constructSimulateGraph(graph, simulator); diff --git a/AlgebraicDataflowArchitectureModel/src/code/ast/PrimitiveType.java b/AlgebraicDataflowArchitectureModel/src/code/ast/PrimitiveType.java index b8d252e..3381022 100644 --- a/AlgebraicDataflowArchitectureModel/src/code/ast/PrimitiveType.java +++ b/AlgebraicDataflowArchitectureModel/src/code/ast/PrimitiveType.java @@ -10,24 +10,16 @@ * @author s-yamagiwa */ public class PrimitiveType extends AnnotatableType { - private models.algebra.Type type; + private String typeName; - public PrimitiveType(models.algebra.Type type) { - this.type = type; - } - - public models.algebra.Type getType() { - return type; - } - - public void setType(models.algebra.Type type) { - this.type = type; + public PrimitiveType(String typeName) { + this.typeName = typeName; } @Override public String toString() { if (getAnnotations().isEmpty()) { - return type.getTypeName(); + return typeName; } StringBuilder builder = new StringBuilder(); @@ -35,7 +27,7 @@ builder.append(annotation.toString()); builder.append(" "); } - builder.append(type.getTypeName()); + builder.append(typeName); return builder.toString(); } diff --git a/AlgebraicDataflowArchitectureModel/src/code/ast/Type.java b/AlgebraicDataflowArchitectureModel/src/code/ast/Type.java index 7861acc..d5291e9 100644 --- a/AlgebraicDataflowArchitectureModel/src/code/ast/Type.java +++ b/AlgebraicDataflowArchitectureModel/src/code/ast/Type.java @@ -7,7 +7,7 @@ * * @author s-yamagiwa */ -public abstract class Type extends ASTNode { +public abstract class Type extends ASTNode implements models.algebra.Type.ITypeImpl { /** * Returns whether this type is a primitive type or not. * diff --git a/AlgebraicDataflowArchitectureModel/src/generators/CodeGenerator.java b/AlgebraicDataflowArchitectureModel/src/generators/CodeGenerator.java index 37bf0f2..4359e3b 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/CodeGenerator.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/CodeGenerator.java @@ -10,7 +10,6 @@ import java.util.Set; import java.util.Stack; -import algorithms.TypeInference; import code.ast.Block; import code.ast.CompilationUnit; import code.ast.FieldDeclaration; @@ -58,9 +57,10 @@ public static final String from = "From"; public static final String _for = "For"; public static final String presenter = "presenter"; - public static final Type presenterType = new Type("SwingPresenter", "SwingPresenter"); + public static final Type presenterType = new Type("SwingPresenter", new code.ast.SimpleType("SwingPresenter")); private static String mainTypeName = null; private static HashMap> componentNames = new HashMap<>(); + protected Map resourceHierarchyToComponent; protected Map>> updateMethods; protected ILanguageSpecific langSpec = null; protected IPlatformSpecific platformSpec = null; @@ -164,6 +164,7 @@ this.langSpec = langSpec; this.platformSpec = platformSpec; this.updateMethods = new HashMap<>(); + this.resourceHierarchyToComponent = new HashMap<>(); ArrayList codes = new ArrayList<>(); Map> dependedRootComponentGraph = null; diff --git a/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromDataFlowGraph.java b/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromDataFlowGraph.java index 4237555..5e406be 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromDataFlowGraph.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromDataFlowGraph.java @@ -9,9 +9,6 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; - -import algorithms.TypeInference; - import java.util.Set; import java.util.Stack; @@ -60,11 +57,9 @@ import simulator.ResourceIdentifier; public class CodeGeneratorFromDataFlowGraph extends CodeGenerator { - protected Map resourceHierarchyToComponent; protected Map> constructorParams; public void generateCodeFromFlowGraph(DataTransferModel model, DataFlowGraph flowGraph, Collection components, ArrayList codes, Map> dependedRootComponentGraph) { - resourceHierarchyToComponent = new HashMap<>(); constructorParams = new HashMap<>(); Map resourceConstructors = new HashMap<>(); List> constructorStatements = new ArrayList<>(); diff --git a/AlgebraicDataflowArchitectureModel/src/generators/ILanguageSpecific.java b/AlgebraicDataflowArchitectureModel/src/generators/ILanguageSpecific.java index 2c89884..eebaa15 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/ILanguageSpecific.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/ILanguageSpecific.java @@ -8,6 +8,7 @@ import models.algebra.Term; import models.algebra.Type; import models.algebra.Variable; +import models.dataConstraintModel.JsonType; import models.dataFlowModel.DataTransferChannel.IResourceStateAccessor; public interface ILanguageSpecific { @@ -19,8 +20,13 @@ FieldDeclaration newFieldDeclaration(Type fieldType, String fieldName); FieldDeclaration newFieldDeclaration(Type fieldType, String fieldName, String fieldInitializer); Type newListType(String compTypeName); + Type newListType(String compTypeName, Type parentListType); Type newMapType(Type keyType, String compTypeName); + Type newMapType(Type keyType, String compTypeName, Type parentMapType); Type newTupleType(List compTypes); + Type newTupleType(List componentTypes, Type parentTupleType); + JsonType newJsonType(); + JsonType newJsonType(Type parentJsonType); VariableDeclaration getVariableDeclaration(Type typeName, String varName); boolean declareField(); String getSelfExp(); @@ -33,8 +39,8 @@ ReturnStatement getReturnStatement(String returnValue); IfStatement getIfStatement(Term condition, Statement block); ForStatement getForStatementForList(Variable varName, Expression list); - EnhancedForStatement getForStatementForCollection(String varName, String varType, String collection); - EnhancedForStatement getForStatementForMap(String varName, String varType, String map); + EnhancedForStatement getForStatementForCollection(VariableDeclaration varDeclaration, String collection); + EnhancedForStatement getForStatementForMap(VariableDeclaration varDeclaration, String map); String getEndForStatement(); String getEndForStatement(String varName); String toComponentName(String name); diff --git a/AlgebraicDataflowArchitectureModel/src/generators/JavaSpecific.java b/AlgebraicDataflowArchitectureModel/src/generators/JavaSpecific.java index d0c42c7..900d9b8 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/JavaSpecific.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/JavaSpecific.java @@ -1,5 +1,6 @@ package generators; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -9,9 +10,20 @@ import models.algebra.Expression; import models.algebra.Type; import models.dataConstraintModel.DataConstraintModel; +import models.dataConstraintModel.JsonType; public class JavaSpecific implements ILanguageSpecific { - public static final Type typeVoid = new Type("Void", "void"); + public static final Type typeVoid = new Type("Void", new code.ast.SimpleType("void")); + public static final code.ast.SimpleType typeObject = new code.ast.SimpleType("Object"); + public static final code.ast.SimpleType typeInteger = new code.ast.SimpleType("Integer"); + public static final code.ast.SimpleType typeDouble = new code.ast.SimpleType("Double"); + public static final code.ast.SimpleType typeString = new code.ast.SimpleType("String"); + public static final code.ast.SimpleType typeList = new code.ast.SimpleType("List"); + public static final code.ast.SimpleType typeArrayList = new code.ast.SimpleType("ArrayList"); + public static final code.ast.SimpleType typeMap = new code.ast.SimpleType("Map"); + public static final code.ast.SimpleType typeMapEntry = new code.ast.SimpleType("Map.Entry"); + public static final code.ast.SimpleType typeHashMap = new code.ast.SimpleType("HashMap"); + public static final code.ast.SimpleType typePair = new code.ast.SimpleType("Pair"); public static final String self = "this"; @Override @@ -59,35 +71,62 @@ @Override public Type newListType(String compTypeName) { - return new Type("List", "ArrayList<>", "List<" + compTypeName + ">", DataConstraintModel.typeList); + return newListType(compTypeName, DataConstraintModel.typeList); + } + + @Override + public Type newListType(String compTypeName, Type parentListType) { + List typeArgs = new ArrayList<>(); + typeArgs.add(new code.ast.SimpleType(compTypeName)); + return new Type("List", new code.ast.ParameterizedType(typeArrayList), new code.ast.ParameterizedType(JavaSpecific.typeList, typeArgs), parentListType); } @Override public Type newMapType(Type keyType, String valueTypeName) { - return new Type("Map", "HashMap<>", "Map<" + keyType.getImplementationTypeName() + ", " + valueTypeName + ">", DataConstraintModel.typeMap); + return newMapType(keyType, valueTypeName, DataConstraintModel.typeMap); + } + + @Override + public Type newMapType(Type keyType, String valueTypeName, Type parentMapType) { + List typeArgs = new ArrayList<>(); + typeArgs.add((code.ast.Type) keyType.getInterfaceType()); + typeArgs.add(new code.ast.SimpleType(valueTypeName)); + return new Type("Map", new code.ast.ParameterizedType(typeHashMap), new code.ast.ParameterizedType(JavaSpecific.typeMap, typeArgs), parentMapType); } @Override public Type newTupleType(List componentTypes) { - String implTypeName = "AbstractMap.SimpleEntry<>"; - String interfaceTypeName = "Map.Entry<$x>"; + return newTupleType(componentTypes, DataConstraintModel.typeTuple); + } + + @Override + public Type newTupleType(List componentTypes, Type parentTupleType) { + code.ast.Type implType = new code.ast.SimpleType("AbstractMap.SimpleEntry"); + code.ast.Type interfaceType = typeMapEntry; 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>"); + interfaceType = (code.ast.Type) componentTypes.get(componentTypes.size() - 1).getInterfaceType(); + for (int i = componentTypes.size() - 2; i >= 0; i--) { + List typeArgs = new ArrayList<>(); + typeArgs.add((code.ast.Type) componentTypes.get(i).getInterfaceType()); + typeArgs.add(interfaceType); + interfaceType = new code.ast.ParameterizedType(typeMapEntry, typeArgs); } - 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, DataConstraintModel.typeTuple); + Type newTupleType = new Type("Tuple", implType, interfaceType, parentTupleType); return newTupleType; } + + @Override + public JsonType newJsonType() { + return new JsonType("Json", new code.ast.ParameterizedType(typeHashMap), new code.ast.ParameterizedType(typeMap, List.of(typeString, typeObject))); + } + + @Override + public JsonType newJsonType(Type parentJsonType) { + JsonType jsonType = newJsonType(); + jsonType.addParentType(parentJsonType); + return jsonType; + } @Override public VariableDeclaration getVariableDeclaration(Type typeName, String varName) { @@ -205,10 +244,9 @@ } @Override - public EnhancedForStatement getForStatementForCollection(String varName, String varType, String collection) { + public EnhancedForStatement getForStatementForCollection(VariableDeclaration varDeclaration, String collection) { EnhancedForStatement enhancedForStatement = new EnhancedForStatement(); - VariableDeclaration varDeclaration = new VariableDeclaration(new models.algebra.Type(varName,varType), varName); enhancedForStatement.setParameter(varDeclaration); enhancedForStatement.setExpression(new code.ast.Variable(collection)); @@ -216,10 +254,9 @@ } @Override - public EnhancedForStatement getForStatementForMap(String varName, String varType, String map) { + public EnhancedForStatement getForStatementForMap(VariableDeclaration varDeclaration, String map) { EnhancedForStatement enhancedForStatement = new EnhancedForStatement(); - - VariableDeclaration varDeclaration = new VariableDeclaration(new models.algebra.Type(varName,varType), varName); + enhancedForStatement.setParameter(varDeclaration); enhancedForStatement.setExpression(new code.ast.Variable(map + ".keySet()")); diff --git a/AlgebraicDataflowArchitectureModel/src/generators/JerseyMethodBodyGenerator.java b/AlgebraicDataflowArchitectureModel/src/generators/JerseyMethodBodyGenerator.java index 9552937..afea683 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/JerseyMethodBodyGenerator.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/JerseyMethodBodyGenerator.java @@ -11,7 +11,6 @@ import java.util.Set; import java.util.Stack; -import algorithms.TypeInference; import code.ast.CodeUtil; import code.ast.CompilationUnit; import code.ast.MethodDeclaration; diff --git a/AlgebraicDataflowArchitectureModel/src/generators/JerseySpecific.java b/AlgebraicDataflowArchitectureModel/src/generators/JerseySpecific.java index a9f4c3c..33a9686 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/JerseySpecific.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/JerseySpecific.java @@ -3,7 +3,6 @@ import java.util.List; import java.util.Map; -import algorithms.TypeInference; import code.ast.Annotation; import code.ast.CompilationUnit; import code.ast.FieldDeclaration; @@ -15,7 +14,7 @@ import models.dataConstraintModel.DataConstraintModel; public class JerseySpecific extends RestApiSpecific { - public static final Type typeClient = new Type("Client", "Client"); + public static final Type typeClient = new Type("Client", new code.ast.SimpleType("Client")); public JerseySpecific() { langSpec = new JavaSpecific(); diff --git a/AlgebraicDataflowArchitectureModel/src/generators/TypeInference.java b/AlgebraicDataflowArchitectureModel/src/generators/TypeInference.java new file mode 100644 index 0000000..bd8418c --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/generators/TypeInference.java @@ -0,0 +1,2380 @@ +package generators; + +import java.util.AbstractMap; +import java.util.ArrayList; +import java.util.Arrays; +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.Node; +import models.algebra.Constant; +import models.algebra.Expression; +import models.algebra.Position; +import models.algebra.Symbol; +import models.algebra.Term; +import models.algebra.Type; +import models.algebra.Variable; +import models.dataConstraintModel.Channel; +import models.dataConstraintModel.ChannelMember; +import models.dataConstraintModel.DataConstraintModel; +import models.dataConstraintModel.JsonType; +import models.dataConstraintModel.ResourceHierarchy; +import models.dataConstraintModel.ResourcePath; +import models.dataConstraintModel.Selector; +import models.dataConstraintModel.StateTransition; +import models.dataFlowModel.DataTransferModel; +import models.dataFlowModel.ResourceNode; + +/** + * Type inference for data transfer model + * + * @author Nitta + * + */ +public class TypeInference { + private ILanguageSpecific langSpec; + private Map listTypes = new HashMap<>(); + private Map listComponentTypes = new HashMap<>(); + private Map, Type> tupleTypes = new HashMap<>(); + private Map> tupleComponentTypes = new HashMap<>(); + private Map pairTypes = new HashMap<>(); + private Map pairComponentTypes = new HashMap<>(); + private Map, Type> mapTypes = new HashMap<>(); + private Map> mapComponentTypes = new HashMap<>(); + private Map, Type> jsonTypes = new HashMap<>(); + private Map> jsonMemberTypes = new HashMap<>(); + + public TypeInference(ILanguageSpecific langSpec) { + this.langSpec = langSpec; + } + + public Type getListType(Type compType) { + return listTypes.get(compType); + } + + public Type getListComponentType(Type listType) { + return listComponentTypes.get(listType); + } + + public Collection getListTypes() { + return listTypes.values(); + } + + public Type getTupleType(List compTypes) { + return tupleTypes.get(compTypes); + } + + public List getTupleComponentTypes(Type tupleType) { + return tupleComponentTypes.get(tupleType); + } + + public Collection getTupleTypes() { + return tupleTypes.values(); + } + + public Type getPairType(Type compType) { + return pairTypes.get(compType); + } + + public Type getPairComponentType(Type pairType) { + return pairComponentTypes.get(pairType); + } + + public Type getMapType(List compTypes) { + return mapTypes.get(compTypes); + } + + public List getMapComponentTypes(Type mapType) { + return mapComponentTypes.get(mapType); + } + + public Type getJsonType(Map memberTypes) { + return jsonTypes.get(memberTypes); + } + + public Map getJsonMemberTypes(Type jsonType) { + return jsonMemberTypes.get(jsonType); + } + + public void infer(DataTransferModel model) { + Map> resources = new HashMap<>(); + Map> resourcePathParams = new HashMap<>(); + Map variables = new HashMap<>(); + Map, Type>>> messages = new HashMap<>(); + Map consOrSet = new HashMap<>(); + Map tuple = new HashMap<>(); + Map pair = new HashMap<>(); + Map map = new HashMap<>(); + Map json = new HashMap<>(); + + // Maps from the objectId of each expression to its belonging group that has the same type as the expression + Map> expToResource = new HashMap<>(); + Map> expToPathParams = new HashMap<>(); + Map> expToVariable = new HashMap<>(); + Map> expToMessage = new HashMap<>(); + Map>> expToConsOrSet = new HashMap<>(); + Map>> expToTuple = new HashMap<>(); + Map>> expToPair = new HashMap<>(); + Map>> expToMap = new HashMap<>(); + Map>> expToJson = new HashMap<>(); + + // Maps from the objectId of each group to the set of updated expressions. + Map> updateFromResource = new HashMap<>(); + Set updateFromResourceOwnership = new HashSet<>(); + Map> updateFromVariable = new HashMap<>(); + Map> updateFromMessage = new HashMap<>(); + Map> updateFromConsOrSet = new HashMap<>(); + Map> updateFromTuple = new HashMap<>(); + Map> updateFromPair = new HashMap<>(); + Map> updateFromMap = new HashMap<>(); + Map> updateFromJson = new HashMap<>(); + + listComponentTypes.put(DataConstraintModel.typeList, null); + listComponentTypes.put(DataConstraintModel.typeListInt, DataConstraintModel.typeInt); + listComponentTypes.put(DataConstraintModel.typeListStr, DataConstraintModel.typeString); + listTypes.put(DataConstraintModel.typeInt, DataConstraintModel.typeListInt); + listTypes.put(DataConstraintModel.typeString, DataConstraintModel.typeListStr); + pairComponentTypes.put(DataConstraintModel.typePair, null); + pairComponentTypes.put(DataConstraintModel.typePairInt, DataConstraintModel.typeInt); + pairComponentTypes.put(DataConstraintModel.typePairStr, DataConstraintModel.typeString); + pairComponentTypes.put(DataConstraintModel.typePairDouble, DataConstraintModel.typeDouble); + pairTypes.put(DataConstraintModel.typeInt, DataConstraintModel.typePairInt); + pairTypes.put(DataConstraintModel.typeString, DataConstraintModel.typePairStr); + pairTypes.put(DataConstraintModel.typeDouble, DataConstraintModel.typePairDouble); + tupleComponentTypes.put(DataConstraintModel.typeTuple, Arrays.asList(new Type[] { null, null })); + mapComponentTypes.put(DataConstraintModel.typeMap, Arrays.asList(new Type[] { null, null })); + + // 1. Collect type information from the architecture model. + Collection channels = new HashSet<>(model.getInputChannels()); + channels.addAll(model.getChannels()); + for (Channel ch : channels) { + // 1.1 Group expressions by resources. + IGroupExpressionsByResource groupExpressionsByResource = new IGroupExpressionsByResource() { + public void groupForChannel(Channel ch) { + for (ChannelMember cm : ch.getChannelMembers()) { + StateTransition st = cm.getStateTransition(); + ResourceHierarchy res = cm.getResource().getResourceHierarchy(); + List identicalResources = resources.get(res); + if (identicalResources == null) { + identicalResources = new ArrayList<>(); + resources.put(res, identicalResources); + } + identicalResources.add(st.getCurStateExpression()); + expToResource.put(System.identityHashCode(st.getCurStateExpression()), identicalResources); + if (st.getNextStateExpression() != null) { + identicalResources.add(st.getNextStateExpression()); + expToResource.put(System.identityHashCode(st.getNextStateExpression()), identicalResources); + } + Map updatedExps = getUpdateSet(updateFromResource, identicalResources); + Type resType = res.getResourceStateType(); + Expression exp = st.getCurStateExpression(); + Type expType = getExpTypeIfUpdatable(resType, exp); + if (expType != null) { + res.setResourceStateType(expType); + for (Expression resExp : identicalResources) { + 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 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 = res.getResourceStateType(); + exp = st.getNextStateExpression(); + if (exp != null) { + expType = getExpTypeIfUpdatable(resType, exp); + if (expType != null) { + res.setResourceStateType(expType); + for (Expression resExp : identicalResources) { + 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 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); + } + } + } + } + for (Channel childCh: ch.getChildren()) { + groupForChannel(childCh); + } + } + }; + groupExpressionsByResource.groupForChannel(ch); + + // 1.2 Group expressions by variable. + IGroupExpressionsByVariable groupExpressionsByVariable = new IGroupExpressionsByVariable() { + public void groupForChannel(Channel ch) { + for (ChannelMember cm : ch.getChannelMembers()) { + StateTransition st = cm.getStateTransition(); + Map> locals = new HashMap<>(); + Map localTypes = new HashMap<>(); + List allVariables = new ArrayList<>(); + allVariables.addAll(st.getCurStateExpression().getVariables().values()); + allVariables.addAll(st.getMessageExpression().getVariables().values()); + if (st.getNextStateExpression() != null) { + allVariables.addAll(st.getNextStateExpression().getVariables().values()); + } + for (Selector s: ch.getAllSelectors()) { // add channel selectors + if (s.getExpression() instanceof Variable) { + allVariables.add((Variable) s.getExpression()); + } + } + ResourcePath resPath = cm.getResource(); + for (Expression param: resPath.getPathParams()) { // add path parameters + if (param instanceof Variable) { + allVariables.add((Variable) param); + } else if (param instanceof Term) { + allVariables.addAll(((Term) param).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 (Expression v : sameVariable) { + if (v != var) { + if (compareTypes(((Variable) v).getType(), var.getType())) { + ((Variable) 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 (String varName : locals.keySet()) { + variables.put(System.identityHashCode(locals.get(varName)), localTypes.get(varName)); + } + } + for (Channel childCh: ch.getChildren()) { + groupForChannel(childCh); + } + } + }; + groupExpressionsByVariable.groupForChannel(ch); + + // 1.3 Group expressions by message. + IGroupExpressionsByMessage groupExpressionsByMessage = new IGroupExpressionsByMessage() { + public void groupForChannel(Channel rootCh, Channel ch) { + for (ChannelMember cm : ch.getChannelMembers()) { + Expression message = cm.getStateTransition().getMessageExpression(); + if (message instanceof Variable) { + Type msgType = ((Variable) message).getType(); + Map, Type>> msgTypeMap = messages.get(rootCh); + if (msgTypeMap == null) { + msgTypeMap = new HashMap<>(); + messages.put(rootCh, 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(rootCh); + if (msgTypeMap == null) { + msgTypeMap = new HashMap<>(); + messages.put(rootCh, 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); + } + } + } + } + } + } + for (Channel childCh: ch.getChildren()) { + groupForChannel(rootCh, childCh); + } + } + }; + groupExpressionsByMessage.groupForChannel(ch, ch); + + // 1.4 Extract constraints on expressions in each term. + IExtractConstraintsOnExpressionsInTerm extractConstraintsOnExpressionsInTerm = new IExtractConstraintsOnExpressionsInTerm() { + public void extractForChannel(Channel ch) { + for (ChannelMember cm : ch.getChannelMembers()) { + StateTransition st = cm.getStateTransition(); + List terms = new ArrayList<>(); + 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() != null && st.getNextStateExpression() instanceof Term) { + Map subTerms = ((Term) st.getNextStateExpression()).getSubTerms(Term.class); + terms.addAll(subTerms.values()); + } + for (Term t : terms) { + Symbol symbol = t.getSymbol(); + if (symbol.equals(DataConstraintModel.cons) || symbol.equals(DataConstraintModel.set) || symbol.equals(DataConstraintModel.append)) { + // If the root symbol of the term is cons or set. + List consExps = new ArrayList<>(); + consExps.add(t); // list term + updateExpressionBelonging(expToConsOrSet, t, consExps); + if (symbol.equals(DataConstraintModel.cons)) { + // If the root symbol of the term is cons. + for (Expression e : t.getChildren()) { + consExps.add(e); + updateExpressionBelonging(expToConsOrSet, e, consExps); + } + } else if (symbol.equals(DataConstraintModel.append)) { + // If the root symbol of the term is append. + Expression e = t.getChildren().get(1); + consExps.add(e); // list element + updateExpressionBelonging(expToConsOrSet, e, consExps); + e = t.getChildren().get(0); + consExps.add(e); // list argument + updateExpressionBelonging(expToConsOrSet, e, consExps); + } else { + // If the root symbol of the term is set. + Expression e = t.getChildren().get(2); + consExps.add(e); // list element + updateExpressionBelonging(expToConsOrSet, e, consExps); + e = t.getChildren().get(0); + consExps.add(e); // list argument + updateExpressionBelonging(expToConsOrSet, e, consExps); + } + Type newType = getExpTypeIfUpdatable(t.getType(), consExps.get(2)); + if (newType != null) { + // If the type of the 2nd argument of cons (1st argument of set/append) is more concrete than the type of the term. + t.setType(newType); + Map updateCons = getUpdateSet(updateFromConsOrSet, 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 2nd argument of cons (1st argument of set/append). + ((Variable) consExps.get(2)).setType(t.getType()); + Map updateCons = getUpdateSet(updateFromConsOrSet, 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 2nd argument of cons (1st argument of set/append). + ((Term) consExps.get(2)).setType(t.getType()); + Map updateCons = getUpdateSet(updateFromConsOrSet, 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 1st argument of cons (3rd argument of set) 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(updateFromConsOrSet, 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)); + } + } + consOrSet.put(System.identityHashCode(consExps), t.getType()); + } else if (symbol.equals(DataConstraintModel.head) || symbol.equals(DataConstraintModel.get)) { + // If the root symbol of the term is head or get. + List consExps = new ArrayList<>(); + Expression e = t.getChildren().get(0); + consExps.add(e); // list argument + updateExpressionBelonging(expToConsOrSet, e, consExps); + consExps.add(t); // list's component + updateExpressionBelonging(expToConsOrSet, t, consExps); + consExps.add(null); + Type listType = listTypes.get(t.getType()); + if (listType == null && t.getType() != null) { + // Create a new list type. + listType = createNewListType(t.getType(), DataConstraintModel.typeList); + } + Type newListType = getExpTypeIfUpdatable(listType, consExps.get(0)); + if (newListType != null) { + // If the type of the component of the 1st argument is more concrete than the type of the term. + Type newCompType = listComponentTypes.get(newListType); + if (newCompType != null) { + t.setType(newCompType); + Map updateCons = getUpdateSet(updateFromConsOrSet, consExps); + updateCons.put(System.identityHashCode(t), t); + } + consOrSet.put(System.identityHashCode(consExps), newListType); + } else { + // If the type of the term is more concrete than the type of the component of the 1st argument. + if (consExps.get(0) != null && consExps.get(0) instanceof Variable) { + ((Variable) consExps.get(0)).setType(listType); + Map updateCons = getUpdateSet(updateFromConsOrSet, consExps); + updateCons.put(System.identityHashCode(consExps.get(0)), consExps.get(0)); + } else if (consExps.get(0) != null && consExps.get(0) instanceof Term) { + ((Term) consExps.get(0)).setType(listType); + Map updateCons = getUpdateSet(updateFromConsOrSet, consExps); + updateCons.put(System.identityHashCode(consExps.get(0)), consExps.get(0)); + } + consOrSet.put(System.identityHashCode(consExps), listType); + } + } else if (symbol.equals(DataConstraintModel.tail)) { + // If the root symbol of the term is tail. + List consExps = new ArrayList<>(); + consExps.add(t); // list term + updateExpressionBelonging(expToConsOrSet, t, consExps); + consExps.add(null); // list's component + Expression e = t.getChildren().get(0); + consExps.add(e); // list argument + updateExpressionBelonging(expToConsOrSet, e, consExps); + Type newType = getExpTypeIfUpdatable(t.getType(), consExps.get(2)); + if (newType != null) { + // If the type of the argument is more concrete than the type of the term. + t.setType(newType); + Map updateCons = getUpdateSet(updateFromConsOrSet, consExps); + updateCons.put(System.identityHashCode(t), t); + } else { + Type argType = null; + if (consExps.get(2) != null && consExps.get(2) instanceof Variable) { + argType = ((Variable) consExps.get(2)).getType(); + if (compareTypes(argType, t.getType())) { + // If the type of the term is more concrete than the type of the argument. + ((Variable) consExps.get(2)).setType(t.getType()); + Map updateCons = getUpdateSet(updateFromConsOrSet, consExps); + updateCons.put(System.identityHashCode(consExps.get(2)), consExps.get(2)); + } + } else if (consExps.get(2) != null && consExps.get(2) instanceof Term) { + argType = ((Term) consExps.get(2)).getType(); + if (compareTypes(argType, t.getType())) { + // If the type of the term is more concrete than the type of the argument. + ((Term) consExps.get(2)).setType(t.getType()); + Map updateCons = getUpdateSet(updateFromConsOrSet, consExps); + updateCons.put(System.identityHashCode(consExps.get(2)), consExps.get(2)); + } + } + } + consOrSet.put(System.identityHashCode(consExps), t.getType()); + } else if (symbol.equals(DataConstraintModel.tuple)) { + // If the root symbol of the term is tuple. + List tupleExps = new ArrayList<>(); + List newArgTypesList = new ArrayList<>(); + tupleExps.add(t); // tuple term + updateExpressionBelonging(expToTuple, t, tupleExps); + for (Expression e : t.getChildren()) { + tupleExps.add(e); // tuple's component + updateExpressionBelonging(expToTuple, e, tupleExps); + if (e instanceof Variable) { + newArgTypesList.add(((Variable) e).getType()); + } else if (e instanceof Term) { + newArgTypesList.add(((Term) e).getType()); + } else { + newArgTypesList.add(null); + } + } + if (t.getType() == DataConstraintModel.typeTuple) { + Type newTupleType = tupleTypes.get(newArgTypesList); + if (newTupleType == null) { + // Create new tuple type; + newTupleType = createNewTupleType(newArgTypesList, DataConstraintModel.typeTuple); + } + // Update the type of the tuple term and record the updated expression. + t.setType(newTupleType); + Map updateExps = getUpdateSet(updateFromTuple, tupleExps); + updateExps.put(System.identityHashCode(t), t); + } + tuple.put(System.identityHashCode(tupleExps), t.getType()); + } else if (symbol.equals(DataConstraintModel.pair)) { + // If the root symbol of the term is pair. + List pairExps = new ArrayList<>(); + pairExps.add(t); // pair + updateExpressionBelonging(expToPair, t, pairExps); + if (t.getType() == DataConstraintModel.typePair) { + for (Expression e : t.getChildren()) { + pairExps.add(e); // left/right + updateExpressionBelonging(expToPair, e, pairExps); + Type newArgType = null; + if (e instanceof Variable) { + newArgType = (((Variable) e).getType()); + + } else if (e instanceof Term) { + newArgType = (((Term) e).getType()); + } + + if (newArgType != null) { + Type newPairType = pairTypes.get(newArgType); + if (newPairType != null) { + t.setType(newPairType); + Map updateExps = getUpdateSet(updateFromPair, pairExps); + updateExps.put(System.identityHashCode(t), t); + } + } + } + pair.put(System.identityHashCode(pairExps), 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); // tuple argument + updateExpressionBelonging(expToTuple, arg, tupleExps); + tupleExps.add(t); // first component + updateExpressionBelonging(expToTuple, t, tupleExps); + tupleExps.add(null); // second component + 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 newCompTypeList = new ArrayList<>(); + newCompTypeList.add(t.getType()); + newCompTypeList.add(null); + newTupleType = tupleTypes.get(newCompTypeList); + if (newTupleType == null) { + // Create new tuple type; + newTupleType = createNewTupleType(newCompTypeList, DataConstraintModel.typeTuple); + } + } + if (argType != newTupleType && newTupleType != null) { + // Update the type of the tuple argument and record the updated expression. + 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); // tuple argument + updateExpressionBelonging(expToTuple, arg, tupleExps); + tupleExps.add(null); // first component + tupleExps.add(t); // second component + updateExpressionBelonging(expToTuple, 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 newCompTypeList = new ArrayList<>(); + newCompTypeList.add(null); + if (DataConstraintModel.typeTuple.isAncestorOf(t.getType())) { + List sndTypes = tupleComponentTypes.get(t.getType()); + if (sndTypes != null) { + for (Type t2: sndTypes) { + newCompTypeList.add(t2); + } + } else { + newCompTypeList.add(t.getType()); + } + } else { + newCompTypeList.add(t.getType()); + } + newTupleType = tupleTypes.get(newCompTypeList); + if (newTupleType == null) { + // Create new tuple type; + newTupleType = createNewTupleType(newCompTypeList, DataConstraintModel.typeTuple); + } + } + if (argType != newTupleType && newTupleType != null) { + // Update the type of the tuple argument and record the updated expression. + 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.left)) { + // If the root symbol of the term is left. + List pairExps = new ArrayList<>(); + Expression arg = t.getChildren().get(0); + pairExps.add(arg); // pair + updateExpressionBelonging(expToPair, arg, pairExps); + pairExps.add(t); // left + updateExpressionBelonging(expToPair, t, pairExps); + pairExps.add(null); // right + Type argType = null; + if (arg instanceof Variable) { + argType = ((Variable) arg).getType(); + } else if (arg instanceof Term) { + argType = ((Term) arg).getType(); + } + Type newPairType = DataConstraintModel.typePair; + if (argType == DataConstraintModel.typePair && t.getType() != null) { + List newCompTypeList = new ArrayList<>(); + newCompTypeList.add(t.getType()); + newCompTypeList.add(null); + newPairType = pairTypes.get(newCompTypeList); + if (newPairType == null) { + // Create new tuple type; + newPairType = createNewTupleType(newCompTypeList, DataConstraintModel.typePair); + } + } + if (argType != newPairType && newPairType != null) { + if (arg instanceof Variable) { + ((Variable) arg).setType(newPairType); + argType = newPairType; + } else if (arg instanceof Term) { + ((Term) arg).setType(newPairType); + argType = newPairType; + } + Map updateExps = getUpdateSet(updateFromPair, pairExps); + updateExps.put(System.identityHashCode(arg), arg); + } + pair.put(System.identityHashCode(pairExps), argType); + } else if (symbol.equals(DataConstraintModel.right)) { + // If the root symbol of the term is right. + List pairExps = new ArrayList<>(); + Expression arg = t.getChildren().get(0); + pairExps.add(arg); // pair + updateExpressionBelonging(expToPair, arg, pairExps); + pairExps.add(null); // left + pairExps.add(t); // right + updateExpressionBelonging(expToPair, t, pairExps); + Type argType = null; + if (arg instanceof Variable) { + argType = ((Variable) arg).getType(); + } else if (arg instanceof Term) { + argType = ((Term) arg).getType(); + } + Type newPairType = DataConstraintModel.typePair; + if (argType == DataConstraintModel.typePair && t.getType() != null) { + List newCompTypeList = new ArrayList<>(); + newCompTypeList.add(null); + newCompTypeList.add(t.getType()); + newPairType = pairTypes.get(newCompTypeList); + if (newPairType == null) { + // Create new tuple type; + newPairType = createNewTupleType(newCompTypeList, DataConstraintModel.typePair); + } + } + if (argType != newPairType && newPairType != null) { + if (arg instanceof Variable) { + ((Variable) arg).setType(newPairType); + argType = newPairType; + } else if (arg instanceof Term) { + ((Term) arg).setType(newPairType); + argType = newPairType; + } + Map updateExps = getUpdateSet(updateFromPair, pairExps); + updateExps.put(System.identityHashCode(arg), arg); + } + pair.put(System.identityHashCode(pairExps), argType); + } else if (symbol.equals(DataConstraintModel.lookup)) { + // If the root symbol of the term is lookup. + List mapExps = new ArrayList<>(); + Expression arg1 = t.getChildren().get(0); // map + mapExps.add(arg1); + updateExpressionBelonging(expToMap, arg1, mapExps); + Expression arg2 = t.getChildren().get(1); // key + mapExps.add(arg2); + updateExpressionBelonging(expToMap, arg2, mapExps); + mapExps.add(t); // value + updateExpressionBelonging(expToMap, t, mapExps); + Type arg1Type = null; + if (arg1 instanceof Variable) { + arg1Type = ((Variable) arg1).getType(); + } else if (arg1 instanceof Term) { + arg1Type = ((Term) arg1).getType(); + } + List newCompTypeList = new ArrayList<>(); + if (arg2 instanceof Variable) { + newCompTypeList.add(((Variable) arg2).getType()); + } else if (arg2 instanceof Term) { + newCompTypeList.add(((Term) arg2).getType()); + } else { + newCompTypeList.add(null); + } + newCompTypeList.add(t.getType()); + if (arg1Type == DataConstraintModel.typeMap || arg1Type == null) { + Type newMapType = mapTypes.get(newCompTypeList); + if (newMapType == null) { + // Create new tuple type; + newMapType = createNewMapType(newCompTypeList, DataConstraintModel.typeMap); + } + // Update the type of the map argument and record the updated expression. + if (arg1 instanceof Variable) { + ((Variable) arg1).setType(newMapType); + arg1Type = newMapType; + } else if (arg1 instanceof Term) { + ((Term) arg1).setType(newMapType); + arg1Type = newMapType; + } + Map updateExps = getUpdateSet(updateFromMap, mapExps); + updateExps.put(System.identityHashCode(arg1), arg1); + } + map.put(System.identityHashCode(mapExps), arg1Type); + } else if (symbol.equals(DataConstraintModel.insert)) { + // If the root symbol of the term is insert. + List mapExps = new ArrayList<>(); + mapExps.add(t); // map + updateExpressionBelonging(expToMap, t, mapExps); + Expression arg1 = t.getChildren().get(1); // key + mapExps.add(arg1); + updateExpressionBelonging(expToMap, arg1, mapExps); + Expression arg2 = t.getChildren().get(2); // value + mapExps.add(arg2); + updateExpressionBelonging(expToMap, arg2, mapExps); + Expression arg0 = t.getChildren().get(0); // map + mapExps.add(arg0); + updateExpressionBelonging(expToMap, arg0, mapExps); + Type termType = t.getType(); + List newCompTypeList = new ArrayList<>(); + if (arg1 instanceof Variable) { + newCompTypeList.add(((Variable) arg1).getType()); + } else if (arg1 instanceof Term) { + newCompTypeList.add(((Term) arg1).getType()); + } else { + newCompTypeList.add(null); + } + if (arg2 instanceof Variable) { + newCompTypeList.add(((Variable) arg2).getType()); + } else if (arg2 instanceof Term) { + newCompTypeList.add(((Term) arg2).getType()); + } else { + newCompTypeList.add(null); + } + Type newTermType = getExpTypeIfUpdatable(termType, mapExps.get(3)); + if (newTermType != null) { + // If the type of the 1st argument of insert is more concrete than the type of the term. + t.setType(newTermType); + termType = newTermType; + Map updateExps = getUpdateSet(updateFromMap, mapExps); + updateExps.put(System.identityHashCode(t), t); + } else { + Type arg3Type = null; + if (mapExps.get(3) != null && mapExps.get(3) instanceof Variable) { + arg3Type = ((Variable) mapExps.get(3)).getType(); + if (compareTypes(arg3Type, t.getType())) { + // If the type of the term is more concrete than the type of the 1st argument of insert. + ((Variable) mapExps.get(3)).setType(t.getType()); + Map updateExps = getUpdateSet(updateFromMap, mapExps); + updateExps.put(System.identityHashCode(mapExps.get(3)), mapExps.get(3)); + } + } else if (mapExps.get(3) != null && mapExps.get(3) instanceof Term) { + arg3Type = ((Term) mapExps.get(3)).getType(); + if (compareTypes(arg3Type, t.getType())) { + // If the type of the term is more concrete than the type of the 1st argument of insert. + ((Term) mapExps.get(3)).setType(t.getType()); + Map updateExps = getUpdateSet(updateFromMap, mapExps); + updateExps.put(System.identityHashCode(mapExps.get(3)), mapExps.get(3)); + } + } + } + if (termType == DataConstraintModel.typeMap || termType == null) { + Type newMapType = mapTypes.get(newCompTypeList); + if (newMapType == null) { + // Create new tuple type; + newMapType = createNewMapType(newCompTypeList, DataConstraintModel.typeMap); + } + // Update the type of the map term and record the updated expression. + t.setType(newMapType); + Map updateExps = getUpdateSet(updateFromMap, mapExps); + updateExps.put(System.identityHashCode(t), t); + if (mapExps.get(3) != null && mapExps.get(3) instanceof Variable) { + ((Variable) mapExps.get(3)).setType(newMapType); + updateExps.put(System.identityHashCode(mapExps.get(3)), mapExps.get(3)); + } else if (mapExps.get(3) != null && mapExps.get(3) instanceof Term) { + ((Term) mapExps.get(3)).setType(newMapType); + updateExps.put(System.identityHashCode(mapExps.get(3)), mapExps.get(3)); + } + termType = newMapType; + } + map.put(System.identityHashCode(mapExps), termType); + } else if (symbol.equals(DataConstraintModel.addMember)) { + // If the root symbol of the term is addMember (addMember(json, key, value)). + List dotExps = new ArrayList<>(); + Expression jsonArg = t.getChildren().get(0); + Expression keyArg = t.getChildren().get(1); + Expression valueArg = t.getChildren().get(2); + dotExps.add(t); // json + updateExpressionBelonging(expToJson, t, dotExps); + dotExps.add(keyArg); // key + updateExpressionBelonging(expToJson, keyArg, dotExps); + dotExps.add(valueArg); // value + updateExpressionBelonging(expToJson, valueArg, dotExps); + dotExps.add(jsonArg); // json + updateExpressionBelonging(expToJson, jsonArg, dotExps); + Type jsonType = t.getType(); + Type valueType = null; + if (valueArg instanceof Variable) { + valueType = ((Variable) valueArg).getType(); + } else if (valueArg instanceof Term) { + valueType = ((Term) valueArg).getType(); + } + String keyName = null; + if (keyArg instanceof Constant) { + keyName = ((Constant) keyArg).getSymbol().getName(); + } + Type jsonArgType = null; + if (jsonArg instanceof Variable) { + jsonArgType = ((Variable) jsonArg).getType(); + } else if (jsonArg instanceof Term) { + jsonArgType = ((Term) jsonArg).getType(); + } + Type newJsonType = DataConstraintModel.typeJson; + if (jsonType == DataConstraintModel.typeJson && jsonArgType != null && keyName != null) { + Map newMemberTypes = new HashMap<>(((JsonType) jsonArgType).getMemberTypes()); + newMemberTypes.put(keyName, valueType); + newJsonType = jsonTypes.get(newMemberTypes); + if (newJsonType == null) { + // Create new json type; + newJsonType = createNewJsonType(newMemberTypes, DataConstraintModel.typeJson); + } + } + if (jsonType != newJsonType && newJsonType != null && !newJsonType.isAncestorOf(jsonType)) { + // Update the type of the json term and record the updated expression. + t.setType(newJsonType); + jsonType = newJsonType; + Map updateExps = getUpdateSet(updateFromJson, dotExps); + updateExps.put(System.identityHashCode(t), t); + } + json.put(System.identityHashCode(dotExps), jsonType); + } else if (symbol.equals(DataConstraintModel.dot)) { + // If the root symbol of the term is dot (json.property). + List dotExps = new ArrayList<>(); + Expression jsonArg = t.getChildren().get(0); + Expression keyArg = t.getChildren().get(1); + dotExps.add(jsonArg); // json + updateExpressionBelonging(expToJson, jsonArg, dotExps); + dotExps.add(keyArg); // key + updateExpressionBelonging(expToJson, keyArg, dotExps); + dotExps.add(t); // value + updateExpressionBelonging(expToJson, t, dotExps); + dotExps.add(null); // json + Type jsonType = null; + if (jsonArg instanceof Variable) { + jsonType = ((Variable) jsonArg).getType(); + } else if (jsonArg instanceof Term) { + jsonType = ((Term) jsonArg).getType(); + } + String keyName = null; + if (keyArg instanceof Constant) { + keyName = ((Constant) keyArg).getSymbol().getName(); + } + Type newJsonType = DataConstraintModel.typeJson; + if (jsonType == DataConstraintModel.typeJson && t.getType() != null && keyName != null) { + Map newMemberTypes = new HashMap<>(); + newMemberTypes.put(keyName, t.getType()); + newJsonType = jsonTypes.get(newMemberTypes); + if (newJsonType == null) { + // Create new json type; + newJsonType = createNewJsonType(newMemberTypes, DataConstraintModel.typeJson); + } + } + if (jsonType != newJsonType && newJsonType != null && !newJsonType.isAncestorOf(jsonType)) { + // Update the type of the json argument and record the updated expression. + if (jsonArg instanceof Variable) { + ((Variable) jsonArg).setType(newJsonType); + jsonType = newJsonType; + } else if (jsonArg instanceof Term) { + ((Term) jsonArg).setType(newJsonType); + jsonType = newJsonType; + } + Map updateExps = getUpdateSet(updateFromJson, dotExps); + updateExps.put(System.identityHashCode(jsonArg), jsonArg); + } + json.put(System.identityHashCode(dotExps), jsonType); + } else if (symbol.equals(DataConstraintModel.dotParam)) { + // If the root symbol of the term is dot (json.{param}). + List dotExps = new ArrayList<>(); + Expression jsonArg = t.getChildren().get(0); + Expression keyArg = t.getChildren().get(1); + dotExps.add(jsonArg); // json (list/map) + updateExpressionBelonging(expToJson, jsonArg, dotExps); + dotExps.add(null); // key + dotExps.add(t); // value + updateExpressionBelonging(expToJson, t, dotExps); + dotExps.add(null); // json + Type jsonType = null; + if (jsonArg instanceof Variable) { + jsonType = ((Variable) jsonArg).getType(); + } else if (jsonArg instanceof Term) { + jsonType = ((Term) jsonArg).getType(); + } + Type keyType = null; + if (keyArg instanceof Variable) { + keyType = ((Variable) keyArg).getType(); + } else if (keyArg instanceof Term) { + keyType = ((Term) keyArg).getType(); + } + Type newJsonType = null; + if (keyType == DataConstraintModel.typeInt) { + newJsonType = DataConstraintModel.typeList; + } else if (keyType == DataConstraintModel.typeString) { + newJsonType = DataConstraintModel.typeMap; + } + if (t.getType() != null) { + if ((jsonType == DataConstraintModel.typeList)) { + newJsonType = listTypes.get(t.getType()); + if (newJsonType == null) { + // Create new list type; + newJsonType = createNewListType(t.getType(), DataConstraintModel.typeList); + } + } else if (jsonType == DataConstraintModel.typeMap) { + List keyValueTypes = Arrays.asList(new Type[] {DataConstraintModel.typeString, t.getType()}); + newJsonType = mapTypes.get(keyValueTypes); + if (newJsonType == null) { + // Create new map type; + newJsonType = createNewMapType(keyValueTypes, DataConstraintModel.typeMap); + } + } + } + if (jsonType != newJsonType && newJsonType != null && !newJsonType.isAncestorOf(jsonType)) { + // Update the type of the json argument and record the updated expression. + if (jsonArg instanceof Variable) { + ((Variable) jsonArg).setType(newJsonType); + jsonType = newJsonType; + } else if (jsonArg instanceof Term) { + ((Term) jsonArg).setType(newJsonType); + jsonType = newJsonType; + } + Map updateExps = getUpdateSet(updateFromJson, dotExps); + updateExps.put(System.identityHashCode(jsonArg), jsonArg); + } + json.put(System.identityHashCode(dotExps), jsonType); + } else if (symbol.equals(DataConstraintModel.cond)) { + // If the root symbol of the term is if function. + Expression c1 = t.getChild(1); + Expression c2 = t.getChild(2); + List condTerms = new ArrayList<>(); + condTerms.add(t); + condTerms.add(c1); + condTerms.add(c2); + expToVariable.put(System.identityHashCode(t), condTerms); + expToVariable.put(System.identityHashCode(c1), condTerms); + expToVariable.put(System.identityHashCode(c2), condTerms); + Type condType = t.getType(); + Map updatedVars = getUpdateSet(updateFromVariable, condTerms); + Type child1Type = getExpTypeIfUpdatable(condType, c1); + if (child1Type != null) { + condType = child1Type; + t.setType(child1Type); + updatedVars.put(System.identityHashCode(t), t); + } else { + if (c1 instanceof Variable && compareTypes(((Variable) c1).getType(), condType)) { + ((Variable) c1).setType(condType); + updatedVars.put(System.identityHashCode(c1), c1); + } else if (c1 instanceof Term && compareTypes(((Term) c1).getType(), condType)) { + ((Term) c1).setType(condType); + updatedVars.put(System.identityHashCode(c1), c1); + } + } + Type child2Type = getExpTypeIfUpdatable(condType, c2); + if (child2Type != null) { + condType = 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(), condType)) { + ((Variable) c2).setType(condType); + updatedVars.put(System.identityHashCode(c2), c2); + } else if (c2 instanceof Term && compareTypes(((Term) c2).getType(), condType)) { + ((Term) c2).setType(condType); + updatedVars.put(System.identityHashCode(c2), c2); + } + } + 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<>(); + consExps.add(t); + expToVariable.put(System.identityHashCode(t), consExps); + Type condType = t.getType(); + Map updatedVars = getUpdateSet(updateFromVariable, consExps); + for (int i = 1; i < symbol.getSignature().length; i++) { + Type tc = symbol.getSignature()[i]; + if (tc == DataConstraintModel.typeList) { + Expression e = t.getChildren().get(i - 1); + Type newType = getExpTypeIfUpdatable(condType, e); + if (newType != null) { + condType = newType; + for (Expression e2 : consExps) { + if (e2 instanceof Variable) { + ((Variable) e2).setType(newType); + updatedVars.put(System.identityHashCode(e2), e2); + } else if (e2 instanceof Term) { + ((Term) e2).setType(newType); + updatedVars.put(System.identityHashCode(e2), e2); + } + } + } else { + if (e instanceof Variable && compareTypes(((Variable) e).getType(), condType)) { + ((Variable) e).setType(condType); + updatedVars.put(System.identityHashCode(e), e); + } else if (e instanceof Term && compareTypes(((Term) e).getType(), condType)) { + ((Term) e).setType(condType); + updatedVars.put(System.identityHashCode(e), e); + } + } + consExps.add(e); + expToVariable.put(System.identityHashCode(e), consExps); + } + } + variables.put(System.identityHashCode(consExps), condType); + } + } + } + for (Channel childCh: ch.getChildren()) { + extractForChannel(childCh); + } + } + }; + extractConstraintsOnExpressionsInTerm.extractForChannel(ch); + + // 1.5 Extract constraints on path parameters and resources. + IExtractConstraintsOnPathParametersAndResources extractConstraintsOnPathParametersAndResources = new IExtractConstraintsOnPathParametersAndResources() { + public void extractForChannel(Channel ch) { + for (ChannelMember cm : ch.getChannelMembers()) { + ResourcePath rPath = cm.getResource(); + while (rPath != null) { + Expression param = rPath.getLastParam(); + if (param != null) { + ResourceHierarchy parent = rPath.getResourceHierarchy().getParent(); + if (parent != null) { + List pathParams = resourcePathParams.get(parent); + if (pathParams == null) { + pathParams = new ArrayList<>(); + resourcePathParams.put(parent, pathParams); + } + pathParams.add(param); + expToPathParams.put(System.identityHashCode(param), pathParams); + Type parentType = parent.getResourceStateType(); + Type paramType = null; + if (param instanceof Variable) { + paramType = ((Variable) param).getType(); + } else if (param instanceof Term) { + paramType = ((Term) param).getType(); + } + if (paramType != null && parentType == null) { + if (paramType.equals(DataConstraintModel.typeString)) { + parentType = DataConstraintModel.typeMap; + } else if (paramType.equals(DataConstraintModel.typeInt)) { + parentType = DataConstraintModel.typeList; + } + if (parentType != null) { + parent.setResourceStateType(parentType); + updateFromResourceOwnership.add(parent); + } + } + } + } + rPath = rPath.getParent(); + } + } + for (Channel childCh: ch.getChildren()) { + extractForChannel(childCh); + } + } + }; + extractConstraintsOnPathParametersAndResources.extractForChannel(ch); + } + + // 1.6 Extract constraints on resource hierarchies. + for (ResourceHierarchy res: model.getResourceHierarchies()) { + if (res.getResourceStateType() != null) { + updateFromResourceOwnership.add(res); + } + } + + // 2. Propagate type information. + while (updateFromResource.size() > 0 || updateFromVariable.size() > 0 || updateFromMessage.size() > 0 + || updateFromConsOrSet.size() > 0 || updateFromTuple.size() > 0 || updateFromPair.size() > 0 + || updateFromMap.size() > 0 || updateFromJson.size() > 0 || updateFromResourceOwnership.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); + updateConsOrSetTypes(resExp, consOrSet, expToConsOrSet, updateFromConsOrSet); + updateTupleTypes(resExp, tuple, expToTuple, updateFromTuple); + updatePairTypes(resExp, pair, expToPair, updateFromPair); + updateMapTypes(resExp, map, expToMap, updateFromMap); + updateJsonTypes(resExp, json, expToJson, updateFromJson); + updateResourcePathParamsTypes(resExp, resourcePathParams, updateFromResourceOwnership); + } + } + 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()) { + Expression var = variableValue.get(i); + updateResourceTypes(var, resources, expToResource, updateFromResource, updateFromResourceOwnership); + updateVaribleTypes(var, variables, expToVariable, updateFromVariable); + updateMessageTypes(var, messages, expToMessage, updateFromMessage); + updateConsOrSetTypes(var, consOrSet, expToConsOrSet, updateFromConsOrSet); + updateTupleTypes(var, tuple, expToTuple, updateFromTuple); + updatePairTypes(var, pair, expToPair, updateFromPair); + updateMapTypes(var, map, expToMap, updateFromMap); + updateJsonTypes(var, json, expToJson, updateFromJson); + updateResourcePathParamsTypes(var, resourcePathParams, updateFromResourceOwnership); + } + } + 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, updateFromResourceOwnership); + updateVaribleTypes(mesExp, variables, expToVariable, updateFromVariable); + updateConsOrSetTypes(mesExp, consOrSet, expToConsOrSet, updateFromConsOrSet); + updateTupleTypes(mesExp, tuple, expToTuple, updateFromTuple); + updatePairTypes(mesExp, pair, expToPair, updateFromPair); + updateMapTypes(mesExp, map, expToMap, updateFromMap); + updateJsonTypes(mesExp, json, expToJson, updateFromJson); + updateResourcePathParamsTypes(mesExp, resourcePathParams, updateFromResourceOwnership); + } + } + if (updateFromConsOrSet.size() > 0) { + Set consKeys = updateFromConsOrSet.keySet(); + Integer consKey = consKeys.iterator().next(); + Map consValue = updateFromConsOrSet.get(consKey); + updateFromConsOrSet.remove(consKey); + for (int i : consValue.keySet()) { + Expression consExp = consValue.get(i); + updateResourceTypes(consExp, resources, expToResource, updateFromResource, updateFromResourceOwnership); + updateVaribleTypes(consExp, variables, expToVariable, updateFromVariable); + updateMessageTypes(consExp, messages, expToMessage, updateFromMessage); + updateConsOrSetTypes(consExp, consOrSet, expToConsOrSet, updateFromConsOrSet); + updateTupleTypes(consExp, tuple, expToTuple, updateFromTuple); + updatePairTypes(consExp, pair, expToPair, updateFromPair); + updateMapTypes(consExp, map, expToMap, updateFromMap); + updateJsonTypes(consExp, json, expToJson, updateFromJson); + } + } + 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, updateFromResourceOwnership); + updateVaribleTypes(tupleExp, variables, expToVariable, updateFromVariable); + updateMessageTypes(tupleExp, messages, expToMessage, updateFromMessage); + updateConsOrSetTypes(tupleExp, consOrSet, expToConsOrSet, updateFromConsOrSet); + updateTupleTypes(tupleExp, tuple, expToTuple, updateFromTuple); + updatePairTypes(tupleExp, pair, expToPair, updateFromPair); + updateMapTypes(tupleExp, map, expToMap, updateFromMap); + updateJsonTypes(tupleExp, json, expToJson, updateFromJson); + } + } + if (updateFromPair.size() > 0) { + Set pairKeys = updateFromPair.keySet(); + Integer pairKey = pairKeys.iterator().next(); + Map pairValue = updateFromPair.get(pairKey); + updateFromPair.remove(pairKey); + for (int i : pairValue.keySet()) { + Expression pairExp = pairValue.get(i); + updateResourceTypes(pairExp, resources, expToResource, updateFromResource, updateFromResourceOwnership); + updateVaribleTypes(pairExp, variables, expToVariable, updateFromVariable); + updateMessageTypes(pairExp, messages, expToMessage, updateFromMessage); + updateConsOrSetTypes(pairExp, consOrSet, expToConsOrSet, updateFromConsOrSet); + updateTupleTypes(pairExp, tuple, expToTuple, updateFromTuple); + updatePairTypes(pairExp, pair, expToPair, updateFromPair); + updateMapTypes(pairExp, map, expToMap, updateFromMap); + updateJsonTypes(pairExp, json, expToJson, updateFromJson); + } + } + if (updateFromMap.size() > 0) { + Set mapKeys = updateFromMap.keySet(); + Integer mapKey = mapKeys.iterator().next(); + Map mapValue = updateFromMap.get(mapKey); + updateFromMap.remove(mapKey); + for (int i : mapValue.keySet()) { + Expression mapExp = mapValue.get(i); + updateResourceTypes(mapExp, resources, expToResource, updateFromResource, updateFromResourceOwnership); + updateVaribleTypes(mapExp, variables, expToVariable, updateFromVariable); + updateMessageTypes(mapExp, messages, expToMessage, updateFromMessage); + updateConsOrSetTypes(mapExp, consOrSet, expToConsOrSet, updateFromConsOrSet); + updateTupleTypes(mapExp, tuple, expToTuple, updateFromTuple); + updatePairTypes(mapExp, pair, expToPair, updateFromPair); + updateMapTypes(mapExp, map, expToMap, updateFromMap); + updateJsonTypes(mapExp, json, expToJson, updateFromJson); + } + } + if (updateFromJson.size() > 0) { + Set jsonKeys = updateFromJson.keySet(); + Integer jsonKey = jsonKeys.iterator().next(); + Map jsonValue = updateFromJson.get(jsonKey); + updateFromJson.remove(jsonKey); + for (int i : jsonValue.keySet()) { + Expression jsonExp = jsonValue.get(i); + updateResourceTypes(jsonExp, resources, expToResource, updateFromResource, updateFromResourceOwnership); + updateVaribleTypes(jsonExp, variables, expToVariable, updateFromVariable); + updateMessageTypes(jsonExp, messages, expToMessage, updateFromMessage); + updateConsOrSetTypes(jsonExp, consOrSet, expToConsOrSet, updateFromConsOrSet); + updateTupleTypes(jsonExp, tuple, expToTuple, updateFromTuple); + updatePairTypes(jsonExp, pair, expToPair, updateFromPair); + updateMapTypes(jsonExp, map, expToMap, updateFromMap); + updateJsonTypes(jsonExp, json, expToJson, updateFromJson); + } + } + if (updateFromResourceOwnership.size() > 0) { + ResourceHierarchy res = updateFromResourceOwnership.iterator().next(); + updateFromResourceOwnership.remove(res); + updateResourceOwnershipTypes(res, resources, expToResource, updateFromResource, updateFromResourceOwnership); + } + } + } + + private void updateExpressionBelonging(Map>> belonging, Expression exp, List group) { + Set> groups = belonging.get(System.identityHashCode(exp)); + if (groups == null) { + groups = new HashSet<>(); + belonging.put(System.identityHashCode(exp), groups); + groups.add(group); + return; + } + if (!groups.contains(group)) { + groups.add(group); + } + } + + private void updateResourceTypes(Expression exp, Map> resources, Map> expToResource, + Map> updateFromResource, Set updateFromResourceOwnership) { + List identicalResources = expToResource.get(System.identityHashCode(exp)); + if (identicalResources == null) return; + for (ResourceHierarchy res: resources.keySet()) { + if (resources.get(res) == identicalResources) { + Type resType = res.getResourceStateType(); + Type newResType = getExpTypeIfUpdatable(resType, exp); + if (newResType != null) { + res.setResourceStateType(newResType); + updateFromResourceOwnership.add(res); // To update parent and children resources + // Update identical resources + Map updateExps = getUpdateSet(updateFromResource, identicalResources); + for (Expression resExp : identicalResources) { + 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 void updateResourcePathParamsTypes(Expression exp, Map> resourcePathParams, Set updateFromResourceOwnership) { + for (ResourceHierarchy parent: resourcePathParams.keySet()) { + List pathParams = resourcePathParams.get(parent); + if (pathParams.contains(exp)) { + Type parentType = parent.getResourceStateType(); + Type paramType = null; + if (exp instanceof Variable) { + paramType = ((Variable) exp).getType(); + } else if (exp instanceof Term) { + paramType = ((Term) exp).getType(); + } + if (paramType != null && parentType == null) { + if (paramType.equals(DataConstraintModel.typeString)) { + parentType = DataConstraintModel.typeMap; + } else if (paramType.equals(DataConstraintModel.typeInt)) { + parentType = DataConstraintModel.typeList; + } + if (parentType != null) { + parent.setResourceStateType(parentType); + updateFromResourceOwnership.add(parent); + } + } + } + } + } + + private void updateResourceOwnershipTypes(ResourceHierarchy res, Map> resources, + Map> expToResource, Map> updateFromResource, Set updateFromResourceOwnership) { + for (ResourceHierarchy parent: resources.keySet()) { + Type resType = res.getResourceStateType(); + Set children = parent.getChildren(); + if (res.equals(parent)) { + // Propagate an update of a parent resource type to its children' types. + if (DataConstraintModel.typeList.isAncestorOf(resType)) { + Type newElementType = listComponentTypes.get(resType); + if (newElementType != null && children != null && children.size() == 1) { + ResourceHierarchy element = children.iterator().next(); + Type elementType = element.getResourceStateType(); + if (compareTypes(elementType, newElementType)) { + element.setResourceStateType(newElementType); + updateFromResourceOwnership.add(element); + } + } + } else if (DataConstraintModel.typeMap.isAncestorOf(resType)) { + List newComponentTypes = mapComponentTypes.get(resType); + if (newComponentTypes != null && newComponentTypes.size() == 2 && children != null && children.size() == 1) { + ResourceHierarchy value = children.iterator().next(); + Type valueType = value.getResourceStateType(); + if (compareTypes(valueType, newComponentTypes.get(1))) { + value.setResourceStateType(newComponentTypes.get(1)); + updateFromResourceOwnership.add(value); + } + } + } else if (DataConstraintModel.typeJson.isAncestorOf(resType)) { + Map newMemberTypes = jsonMemberTypes.get(resType); + if (newMemberTypes != null && newMemberTypes.size() > 0 && children != null && children.size() > 0) { + for (ResourceHierarchy chlid: children) { + String key = chlid.getResourceName(); + Type memberType = chlid.getResourceStateType(); + if (compareTypes(memberType, newMemberTypes.get(key))) { + chlid.setResourceStateType(newMemberTypes.get(key)); + updateFromResourceOwnership.add(chlid); + } + } + } + } + } + if (children.contains(res)) { + // Propagate an update of a child resource type to its parent's type. + Type parentType = parent.getResourceStateType(); + if (parentType != null && DataConstraintModel.typeList.isAncestorOf(parentType)) { + Type oldElementType = listComponentTypes.get(parentType); + if (compareTypes(oldElementType, resType)) { + Type newListType = listTypes.get(resType); + if (newListType == null) { + newListType = createNewListType(resType, parentType); + } + if (newListType != null) { + parent.setResourceStateType(newListType); + updateFromResourceOwnership.add(parent); + } + } + } else if (parentType != null && DataConstraintModel.typeMap.isAncestorOf(parentType)) { + List oldComponentTypes = mapComponentTypes.get(parentType); + if (compareTypes(oldComponentTypes.get(1), resType)) { + List newComponentTypes = Arrays.asList(new Type[] {DataConstraintModel.typeString, resType}); + Type newMapType = mapTypes.get(newComponentTypes); + if (newMapType == null) { + newMapType = createNewMapType(newComponentTypes, parentType); + } + if (newMapType != null) { + parent.setResourceStateType(newMapType); + updateFromResourceOwnership.add(parent); + } + } + } else if (parentType != null && DataConstraintModel.typeJson.isAncestorOf(parentType)) { + Map oldMemberTypes = jsonMemberTypes.get(parentType); + String key= res.getResourceName(); + if (oldMemberTypes == null || compareTypes(oldMemberTypes.get(key), resType)) { + Map newMemberTypes = new HashMap<>(); + if (oldMemberTypes != null) newMemberTypes.putAll(oldMemberTypes); + newMemberTypes.put(key, resType); + Type newJsonType = jsonTypes.get(newMemberTypes); + if (newJsonType == null) { + newJsonType = createNewJsonType(newMemberTypes, parentType); + } + if (newJsonType != null) { + parent.setResourceStateType(newJsonType); + updateFromResourceOwnership.add(parent); + } + } + } + } + } + // Propagate an update of the resource to its expressions. + List identicalResources = resources.get(res); + if (identicalResources != null) { + Type newResType = res.getResourceStateType(); + for (Expression resExp: identicalResources) { + Type resType = null; + if (resExp instanceof Variable) { + resType = ((Variable) resExp).getType(); + } else if (resExp instanceof Term) { + resType = ((Term) resExp).getType(); + } + if (resType == null || compareTypes(resType, newResType)) { + Map updateExps = getUpdateSet(updateFromResource, identicalResources); + 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 void updateVaribleTypes(Expression exp, Map variables, + Map> expToVariable, Map> updateFromVariable) { + List sameVariable = expToVariable.get(System.identityHashCode(exp)); + 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 (Expression v : sameVariable) { + if (v != exp) { + if (v instanceof Variable) { + ((Variable) v).setType(newVarType); + updateVars.put(System.identityHashCode(v), v); + } else if (v instanceof Term) { + ((Term) v).setType(newVarType); + updateVars.put(System.identityHashCode(v), v); + } + } + } + } else { + Map updateVars = getUpdateSet(updateFromVariable, sameVariable); + for (Expression v : sameVariable) { + if (v instanceof Variable) { + Type orgVarType = ((Variable) v).getType(); + if (orgVarType != varType && compareTypes(orgVarType, varType)) { + ((Variable) v).setType(varType); + updateVars.put(System.identityHashCode(v), v); + } + } else if (v instanceof Term) { + Type orgVarType = ((Term) v).getType(); + if (orgVarType != varType && compareTypes(orgVarType, varType)) { + ((Term) v).setType(varType); + updateVars.put(System.identityHashCode(v), v); + } + } + } + } + } + + private 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 (Channel 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 void updateConsOrSetTypes(Expression exp, Map consOrSet, + Map>> expToConsOrSet, Map> updateFromConsOrSet) { + Set> consComponentGroups = expToConsOrSet.get(System.identityHashCode(exp)); + if (consComponentGroups == null) return; + for (List consOrSetComponentGroup: consComponentGroups) { + int idx = consOrSetComponentGroup.indexOf(exp); + switch (idx) { + case 0: + // exp is a list itself. + if (!(exp instanceof Term)) break; + Type listType = consOrSet.get(System.identityHashCode(consOrSetComponentGroup)); + Type expType = getExpTypeIfUpdatable(listType, exp); + if (expType != null) { + consOrSet.put(System.identityHashCode(consOrSetComponentGroup), expType); + Map updateExps = getUpdateSet(updateFromConsOrSet, consOrSetComponentGroup); + if (consOrSetComponentGroup.get(2) instanceof Variable) { + ((Variable) consOrSetComponentGroup.get(2)).setType(expType); + updateExps.put(System.identityHashCode(consOrSetComponentGroup.get(2)), consOrSetComponentGroup.get(2)); + } else if (consOrSetComponentGroup.get(2) instanceof Term) { + ((Term) consOrSetComponentGroup.get(2)).setType(expType); + updateExps.put(System.identityHashCode(consOrSetComponentGroup.get(2)), consOrSetComponentGroup.get(2)); + } + Type compType = listComponentTypes.get(expType); + if (consOrSetComponentGroup.get(1) != null && consOrSetComponentGroup.get(1) instanceof Variable) { + ((Variable) consOrSetComponentGroup.get(1)).setType(compType); + updateExps.put(System.identityHashCode(consOrSetComponentGroup.get(1)), consOrSetComponentGroup.get(1)); + } else if (consOrSetComponentGroup.get(1) != null && consOrSetComponentGroup.get(1) instanceof Term) { + ((Term) consOrSetComponentGroup.get(1)).setType(compType); + updateExps.put(System.identityHashCode(consOrSetComponentGroup.get(1)), consOrSetComponentGroup.get(1)); + } + } + break; + case 1: + // exp is a list's component. + listType = consOrSet.get(System.identityHashCode(consOrSetComponentGroup)); + 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); + } + consOrSet.put(System.identityHashCode(consOrSetComponentGroup), newListType); + Map updateExps = getUpdateSet(updateFromConsOrSet, consOrSetComponentGroup); + if (consOrSetComponentGroup.get(0) instanceof Term) { + ((Term) consOrSetComponentGroup.get(0)).setType(newListType); + updateExps.put(System.identityHashCode(consOrSetComponentGroup.get(0)), consOrSetComponentGroup.get(0)); + } + if (consOrSetComponentGroup.get(2) instanceof Variable) { + ((Variable) consOrSetComponentGroup.get(2)).setType(newListType); + updateExps.put(System.identityHashCode(consOrSetComponentGroup.get(2)), consOrSetComponentGroup.get(2)); + } else if (consOrSetComponentGroup.get(2) instanceof Term) { + ((Term) consOrSetComponentGroup.get(2)).setType(newListType); + updateExps.put(System.identityHashCode(consOrSetComponentGroup.get(2)), consOrSetComponentGroup.get(2)); + } + } + break; + case 2: + // exp is a list itself. + listType = consOrSet.get(System.identityHashCode(consOrSetComponentGroup)); + expType = getExpTypeIfUpdatable(listType, exp); + if (expType != null) { + consOrSet.put(System.identityHashCode(consOrSetComponentGroup), expType); + Map updateExps = getUpdateSet(updateFromConsOrSet, consOrSetComponentGroup); + if (consOrSetComponentGroup.get(0) instanceof Term) { + ((Term) consOrSetComponentGroup.get(0)).setType(expType); + updateExps.put(System.identityHashCode(consOrSetComponentGroup.get(0)), consOrSetComponentGroup.get(0)); + } + compType = listComponentTypes.get(expType); + if (consOrSetComponentGroup.get(1) != null && consOrSetComponentGroup.get(1) instanceof Variable) { + ((Variable) consOrSetComponentGroup.get(1)).setType(compType); + updateExps.put(System.identityHashCode(consOrSetComponentGroup.get(1)), consOrSetComponentGroup.get(1)); + } else if (consOrSetComponentGroup.get(1) != null && consOrSetComponentGroup.get(1) instanceof Term) { + ((Term) consOrSetComponentGroup.get(1)).setType(compType); + updateExps.put(System.identityHashCode(consOrSetComponentGroup.get(1)), consOrSetComponentGroup.get(1)); + } + } + } + } + } + + private void updateTupleTypes(Expression exp, Map tuple, + Map>> expToTuple, Map> updateFromTuple) { + Set> tupleComponentGroups = expToTuple.get(System.identityHashCode(exp)); + if (tupleComponentGroups == null) return; + for (List tupleComponentGroup: tupleComponentGroups) { + int idx = tupleComponentGroup.indexOf(exp); + if (idx == 0) { + // exp is a tuple itself. + Type tupleType = tuple.get(System.identityHashCode(tupleComponentGroup)); + Type newTupleType = getExpTypeIfUpdatable(tupleType, exp); + if (newTupleType != null) { + // Propagate an update of a tuple's type to its components' types. + tuple.put(System.identityHashCode(tupleComponentGroup), newTupleType); + List componentTypes = tupleComponentTypes.get(newTupleType); + Map updateExps = getUpdateSet(updateFromTuple, tupleComponentGroup); + for (int i = 1; i < tupleComponentGroup.size(); i++) { + Expression compExp = tupleComponentGroup.get(i); + if (compExp instanceof Variable) { + Type compType = ((Variable) compExp).getType(); + if (compType != null && DataConstraintModel.typeTuple.isAncestorOf(compType)) { + // If the type of one component (compExp) is also tuple. + Type newExpType = tupleTypes.get(componentTypes.subList(i - 1, componentTypes.size())); + if (newExpType == null) { + // Create new tuple type; + newExpType = createNewTupleType(componentTypes.subList(i - 1, componentTypes.size()), compType); + } + if (compareTypes(compType, newExpType)) { + ((Variable) compExp).setType(newExpType); + updateExps.put(System.identityHashCode(compExp), compExp); + } + } else { + if (i - 1 < componentTypes.size()) { + if (compareTypes(compType, componentTypes.get(i - 1))) { + ((Variable) compExp).setType(componentTypes.get(i - 1)); + updateExps.put(System.identityHashCode(compExp), compExp); + } + } else { + // for insert + if (compareTypes(compType, newTupleType)) { + ((Variable) compExp).setType(newTupleType); + updateExps.put(System.identityHashCode(compExp), compExp); + } + } + } + } else if (compExp instanceof Term) { + Type compType = ((Term) compExp).getType(); + if (compType != null && DataConstraintModel.typeTuple.isAncestorOf(compType)) { + // If the type of one component (compExp) is also tuple. + Type newExpType = tupleTypes.get(componentTypes.subList(i - 1, componentTypes.size())); + if (newExpType == null) { + // Create new tuple type; + newExpType = createNewTupleType(componentTypes.subList(i - 1, componentTypes.size()), compType); + } + if (compareTypes(compType, newExpType)) { + ((Term) compExp).setType(newExpType); + updateExps.put(System.identityHashCode(compExp), compExp); + } + } else { + if (i - 1 < componentTypes.size()) { + if (compareTypes(compType, componentTypes.get(i - 1))) { + ((Term) compExp).setType(componentTypes.get(i - 1)); + updateExps.put(System.identityHashCode(compExp), compExp); + } + } else { + // for insert + if (compareTypes(compType, newTupleType)) { + ((Term) compExp).setType(newTupleType); + updateExps.put(System.identityHashCode(compExp), compExp); + } + } + } + } + } + } + } else { + // exp is a tuple's component. + Type tupleType = tuple.get(System.identityHashCode(tupleComponentGroup)); + List componentTypes = tupleComponentTypes.get(tupleType); + boolean updated = false; + if (idx == 1) { + Type compType = componentTypes.get(idx - 1); + Type newCompType = getExpTypeIfUpdatable(compType, exp); + if (newCompType != null) { + componentTypes = new ArrayList<>(componentTypes); + componentTypes.set(idx - 1, newCompType); + updated = true; + } + } else { + Type expType = null; + if (exp instanceof Term) { + expType = ((Term) exp).getType(); + } else if (exp instanceof Variable) { + expType = ((Variable) exp).getType(); + } + if (expType != null && DataConstraintModel.typeTuple.isAncestorOf(expType)) { + // If the type of the updated component (exp) is also tuple. + List subCompTypes = tupleComponentTypes.get(expType); + componentTypes = new ArrayList<>(componentTypes); + for (int i = 0; i < subCompTypes.size(); i++) { + if (componentTypes.size() < i + 2) { + componentTypes.add(subCompTypes.get(i)); + updated = true; + } else if (compareTypes(componentTypes.get(i + 1), subCompTypes.get(i))) { + componentTypes.set(i + 1, subCompTypes.get(i)); + updated = true; + } + } + } else { + Type compType = componentTypes.get(idx - 1); + Type newCompType = getExpTypeIfUpdatable(compType, exp); + if (newCompType != null) { + componentTypes = new ArrayList<>(componentTypes); + componentTypes.set(idx - 1, newCompType); + updated = true; + } + } + } + if (updated) { + // Propagate an update of a component's type to its container's (tuple's) type. + Type newTupleType = tupleTypes.get(componentTypes); + if (newTupleType == null) { + // Create new tuple type; + newTupleType = createNewTupleType(componentTypes, tupleType); + } + Map updateExps = getUpdateSet(updateFromTuple, tupleComponentGroup); + Expression tupleExp = tupleComponentGroup.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(tupleComponentGroup), newTupleType); + } + } + } + } + + private void updatePairTypes(Expression exp, Map pair, + Map>> expToPair, Map> updateFromPair) { + Set> pairComponentGroups = expToPair.get(System.identityHashCode(exp)); + if (pairComponentGroups == null) return; + for (List pairComponentGroup: pairComponentGroups) { + int idx = pairComponentGroup.indexOf(exp); + if (idx == 0) { + // exp is a pair itself. + Type pairType = pair.get(System.identityHashCode(pairComponentGroup)); + Type newPairType = getExpTypeIfUpdatable(pairType, exp); + if (newPairType != null) { + // Propagate an update of a pair's type to its components' types. + pair.put(System.identityHashCode(pairComponentGroup), newPairType); + Type componentType = pairComponentTypes.get(newPairType); + Map updateExps = getUpdateSet(updateFromPair, pairComponentGroup); + for (int i = 1; i < pairComponentGroup.size(); i++) { + Expression compExp = pairComponentGroup.get(i); + if (compExp instanceof Variable) { + if (compareTypes(((Variable) compExp).getType(), componentType)) { + ((Variable) compExp).setType(componentType); + updateExps.put(System.identityHashCode(compExp), compExp); + } + } else if (compExp instanceof Term) { + if (compareTypes(((Term) compExp).getType(), componentType)) { + ((Term) compExp).setType(componentType); + updateExps.put(System.identityHashCode(compExp), compExp); + } + } + } + } + } else { + // exp is a pair's component. + Type pairType = pair.get(System.identityHashCode(pairComponentGroup)); + Type compType = pairComponentTypes.get(pairType); + Type newCompType = getExpTypeIfUpdatable(compType, exp); + if (newCompType != null) { + // Propagate an update of a component's type to its container's (pair's) type. + Type newPairType = pairTypes.get(compType); + if (newPairType != null) { + Map updateExps = getUpdateSet(updateFromPair, pairComponentGroup); + Expression pairExp = pairComponentGroup.get(0); + if (pairExp instanceof Variable) { + ((Variable) pairExp).setType(newPairType); + updateExps.put(System.identityHashCode(pairExp), pairExp); + } else if (pairExp instanceof Term) { + ((Term) pairExp).setType(newPairType); + updateExps.put(System.identityHashCode(pairExp), pairExp); + } + pair.put(System.identityHashCode(pairComponentGroup), newPairType); + } + } + } + } + } + + private void updateMapTypes(Expression exp, Map map, + Map>> expToMap, Map> updateFromMap) { + Set> mapComponentGroups = expToMap.get(System.identityHashCode(exp)); + if (mapComponentGroups == null) return; + for (List mapComponentGroup: mapComponentGroups) { + int idx = mapComponentGroup.indexOf(exp); + if (idx == 0 || idx == 3) { + // exp is a map itself. + Type mapType = map.get(System.identityHashCode(mapComponentGroup)); + Type newMapType = getExpTypeIfUpdatable(mapType, exp); + if (newMapType != null) { + // Propagate an update of a map's type to its components' types. + map.put(System.identityHashCode(mapComponentGroup), newMapType); + List componentTypes = mapComponentTypes.get(newMapType); + Map updateExps = getUpdateSet(updateFromMap, mapComponentGroup); + for (int i = 1; i < mapComponentGroup.size() && i < 3; i++) { + Expression compExp = mapComponentGroup.get(i); + if (compExp instanceof Variable) { + 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 - 1))) { + ((Term) compExp).setType(componentTypes.get(i - 1)); + updateExps.put(System.identityHashCode(compExp), compExp); + } + } + } + // Propagate an update of a map's type to another map's type. + Expression compExp = null; + if (idx == 0 && mapComponentGroup.size() == 4) { // for insert + compExp = mapComponentGroup.get(3); + } else if (idx == 3) { + compExp = mapComponentGroup.get(0); + } + if (compExp != null) { + if (compExp instanceof Variable) { + if (compareTypes(((Variable) compExp).getType(), newMapType)) { + ((Variable) compExp).setType(newMapType); + updateExps.put(System.identityHashCode(compExp), compExp); + } + } else if (compExp instanceof Term) { + if (compareTypes(((Term) compExp).getType(), newMapType)) { + ((Term) compExp).setType(newMapType); + updateExps.put(System.identityHashCode(compExp), compExp); + } + } + } + } + } else { + // exp is a map's key or value. + Type mapType = map.get(System.identityHashCode(mapComponentGroup)); + List componentTypes = mapComponentTypes.get(mapType); + 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 (map's) type. + componentTypes = new ArrayList<>(componentTypes); + componentTypes.set(idx - 1, newCompType); + Type newMapType = mapTypes.get(componentTypes); + if (newMapType == null) { + // Create new map type; + newMapType = createNewMapType(componentTypes, mapType); + } + Map updateExps = getUpdateSet(updateFromMap, mapComponentGroup); + Expression mapExp = mapComponentGroup.get(0); + if (mapExp instanceof Variable) { + ((Variable) mapExp).setType(newMapType); + updateExps.put(System.identityHashCode(mapExp), mapExp); + } else if (mapExp instanceof Term) { + ((Term) mapExp).setType(newMapType); + updateExps.put(System.identityHashCode(mapExp), mapExp); + } + if (mapComponentGroup.size() == 4) { // for insert + mapExp = mapComponentGroup.get(3); + if (mapExp instanceof Variable) { + ((Variable) mapExp).setType(newMapType); + updateExps.put(System.identityHashCode(mapExp), mapExp); + } else if (mapExp instanceof Term) { + ((Term) mapExp).setType(newMapType); + updateExps.put(System.identityHashCode(mapExp), mapExp); + } + } + map.put(System.identityHashCode(mapComponentGroup), newMapType); + } + } + } + } + + + private void updateJsonTypes(Expression exp, Map json, + Map>> expToJson, Map> updateFromJson) { + Set> jsonMemberGroups = expToJson.get(System.identityHashCode(exp)); + if (jsonMemberGroups == null) return; + for (List jsonMemberGroup: jsonMemberGroups) { + int idx = jsonMemberGroup.indexOf(exp); + if (idx == 3) { + // exp is a json argument (0:t = addMember(3:json, 1:key, 2:value)). + Type jsonType = json.get(System.identityHashCode(jsonMemberGroup)); + if (jsonType != null && jsonMemberTypes.get(jsonType) != null) { + Map memberTypes = new HashMap<>(jsonMemberTypes.get(jsonType)); + Map argMemberTypes = new HashMap<>(memberTypes); + String keyName = null; + Type valueType = null; + if (jsonMemberGroup.get(1) instanceof Constant) { + keyName = ((Constant) jsonMemberGroup.get(1)).getSymbol().getName(); + valueType = ((Constant) jsonMemberGroup.get(1)).getType(); + argMemberTypes.remove(keyName); + } + Type jsonArgType = jsonTypes.get(argMemberTypes); + Type newJsonArgType = getExpTypeIfUpdatable(jsonArgType, exp); + if (newJsonArgType != null && keyName != null) { + // Propagate an update of a json arg's type to its container's (json's) type. + argMemberTypes = ((JsonType) newJsonArgType).getMemberTypes(); + argMemberTypes.put(keyName, valueType); + memberTypes.putAll(argMemberTypes); + Type newJsonType = jsonTypes.get(memberTypes); + if (newJsonType == null) { + // Create new json type. + newJsonType = createNewJsonType(memberTypes, jsonType); + } + // Update the type of the json term and record the updated expression. + Map updateExps = getUpdateSet(updateFromJson, jsonMemberGroup); + Expression jsonExp = jsonMemberGroup.get(0); + if (jsonExp instanceof Variable) { + ((Variable) jsonExp).setType(newJsonType); + updateExps.put(System.identityHashCode(jsonExp), jsonExp); + } else if (jsonExp instanceof Term) { + ((Term) jsonExp).setType(newJsonType); + updateExps.put(System.identityHashCode(jsonExp), jsonExp); + } + json.put(System.identityHashCode(jsonMemberGroup), newJsonType); + } + } + } else if (idx == 2) { + // exp is a value (0:t = addMember(3:json, 1:key, 2:value) or 2:value = dot(0:list/map, 1:key)). + Type jsonType = json.get(System.identityHashCode(jsonMemberGroup)); + Type newJsonType = null; + if (exp instanceof Term && ((Term) exp).getSymbol().equals(DataConstraintModel.dotParam)) { + if (DataConstraintModel.typeList.isAncestorOf(jsonType)) { + Type elementType = listComponentTypes.get(jsonType); + Type newElementType = getExpTypeIfUpdatable(elementType, exp); + if (newElementType != null) { + // Propagate an update of a member's type to its container's (json's) type. + newJsonType = listTypes.get(newElementType); + if (newJsonType == null) { + // Create new json type. + newJsonType = createNewListType(newElementType, jsonType); + } + } + } else if (DataConstraintModel.typeMap.isAncestorOf(jsonType)) { + List keyValueTypes = mapComponentTypes.get(jsonType); + Type newValueType = getExpTypeIfUpdatable(keyValueTypes.get(1), exp); + if (newValueType != null) { + // Propagate an update of a member's type to its container's (json's) type. + List newKeyValueTypes = Arrays.asList(new Type[] {DataConstraintModel.typeString, newValueType}); + newJsonType = mapTypes.get(newKeyValueTypes); + if (newJsonType == null) { + // Create new json type. + newJsonType = createNewMapType(newKeyValueTypes, jsonType); + } + } + } + } else { + Map memberTypes = jsonMemberTypes.get(jsonType); + String keyName = null; + if (jsonMemberGroup.get(1) instanceof Constant) { + keyName = ((Constant) jsonMemberGroup.get(1)).getSymbol().getName(); + } + if (memberTypes != null) { + Type memberType = memberTypes.get(keyName); + Type newMemberType = getExpTypeIfUpdatable(memberType, exp); + if (newMemberType != null && keyName != null) { + // Propagate an update of a member's type to its container's (json's) type. + Map newMemberTypes = new HashMap<>(memberTypes); + newMemberTypes.put(keyName, newMemberType); + newJsonType = jsonTypes.get(newMemberTypes); + if (newJsonType == null) { + // Create new json type. + newJsonType = createNewJsonType(newMemberTypes, jsonType); + } + } + } + } + if (newJsonType != null) { + // Update the type of the json term and record the updated expression. + Map updateExps = getUpdateSet(updateFromJson, jsonMemberGroup); + Expression jsonExp = jsonMemberGroup.get(0); + if (jsonExp instanceof Variable) { + ((Variable) jsonExp).setType(newJsonType); + updateExps.put(System.identityHashCode(jsonExp), jsonExp); + } else if (jsonExp instanceof Term) { + ((Term) jsonExp).setType(newJsonType); + updateExps.put(System.identityHashCode(jsonExp), jsonExp); + } + json.put(System.identityHashCode(jsonMemberGroup), newJsonType); + } + } + } + } + + private Type createNewListType(Type compType, Type parentType) { + String compTypeName = getInterfaceTypeName(compType); + List childrenTypes = getChildrenTypes(parentType, listComponentTypes.keySet()); + Type newListType = langSpec.newListType(compTypeName, parentType); + newListType.addParentType(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 Type createNewMapType(List componentTypes, Type parentMapType) { + List childrenTypes = getChildrenTypes(parentMapType, mapComponentTypes.keySet()); + Type newMapType = langSpec.newMapType(componentTypes.get(0), componentTypes.get(1).toString(), parentMapType); + mapTypes.put(componentTypes, newMapType); + mapComponentTypes.put(newMapType, componentTypes); + for (Type childType : childrenTypes) { + if (compareTypes(childType, newMapType)) { + if (newMapType.getParentTypes().contains(parentMapType)) { + newMapType.replaceParentType(parentMapType, childType); + } else { + newMapType.addParentType(childType); + } + } else if (compareTypes(newMapType, childType)) { + childType.replaceParentType(parentMapType, newMapType); + } + } + return newMapType; + } + + private Type createNewTupleType(List componentTypes, Type parentTupleType) { + List childrenTypes = getChildrenTypes(parentTupleType, tupleComponentTypes.keySet()); + Type newTupleType = langSpec.newTupleType(componentTypes, 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 JsonType createNewJsonType(Map memberTypes, Type parentJsonType) { + List childrenTypes = getChildrenTypes(parentJsonType, jsonMemberTypes.keySet()); + JsonType newJsonType = langSpec.newJsonType(parentJsonType); + for (String key: memberTypes.keySet()) { + newJsonType.addMemberType(key, memberTypes.get(key)); + } + jsonTypes.put(memberTypes, newJsonType); + jsonMemberTypes.put(newJsonType, memberTypes); + for (Type childType : childrenTypes) { + if (compareTypes(childType, newJsonType)) { + if (newJsonType.getParentTypes().contains(parentJsonType)) { + newJsonType.replaceParentType(parentJsonType, childType); + } else { + newJsonType.addParentType(childType); + } + } else if (compareTypes(newJsonType, childType)) { + childType.replaceParentType(parentJsonType, newJsonType); + } + } + return newJsonType; + } + + /** + * Get children types of a given type from given set of types. + * @param parentType a type + * @param allTypes set of types + * @return list of the children types + */ + private List getChildrenTypes(Type parentType, Set allTypes) { + List childrenTypes = new ArrayList<>(); + for (Type childType : allTypes) { + if (childType.getParentTypes().contains(parentType)) { + childrenTypes.add(childType); + } + } + return childrenTypes; + } + + private String getImplementationTypeName(Type type) { + if (type == null) + return "Object"; + String wrapperType = DataConstraintModel.getWrapperType(type); + if (wrapperType != null) + return wrapperType; + return type.getImplementationTypeName(); + } + + private String getInterfaceTypeName(Type type) { + if (type == null) + return "Object"; + String wrapperType = DataConstraintModel.getWrapperType(type); + if (wrapperType != null) + return wrapperType; + return type.getInterfaceTypeName(); + } + + private > 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 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; + } + + /** + * 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 boolean compareTypes(Type originalType, Type newType) { + if (originalType == null) return true; + if (originalType != newType && newType != null) { + if (originalType.isAncestorOf(newType)) return true; + if (newType.isAncestorOf(originalType)) return false; + if (DataConstraintModel.typeMap.isAncestorOf(originalType) + && DataConstraintModel.typeMap.isAncestorOf(newType)) { + List originalCompTypes = mapComponentTypes.get(originalType); + List newCompTypes = mapComponentTypes.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.typeTuple.isAncestorOf(originalType) + && DataConstraintModel.typeTuple.isAncestorOf(newType)) { + List originalCompTypes = tupleComponentTypes.get(originalType); + List newCompTypes = tupleComponentTypes.get(newType); + if (originalCompTypes == null) return true; + originalCompTypes = new ArrayList<>(originalCompTypes); + newCompTypes = new ArrayList<>(newCompTypes); + for (int i = 0; i < originalCompTypes.size(); i++) { + if (originalCompTypes.get(i) != null) { + if (DataConstraintModel.typeTuple.isAncestorOf(originalCompTypes.get(i))) { + // Unfold the nested tuple's types. + Type tupleType = originalCompTypes.remove(i); + for (Type t: tupleComponentTypes.get(tupleType)) { + originalCompTypes.add(t); + } + } + if (newCompTypes.size() - 1 < i) return false; + if (newCompTypes.get(i) != null && DataConstraintModel.typeTuple.isAncestorOf(newCompTypes.get(i))) { + // Unfold the nested tuple's types. + Type tupleType = newCompTypes.remove(i); + for (Type t: tupleComponentTypes.get(tupleType)) { + newCompTypes.add(t); + } + } + if (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; + } + if (DataConstraintModel.typeJson.isAncestorOf(originalType) && DataConstraintModel.typeJson.isAncestorOf(newType)) { + Map originalMemberTypes = jsonMemberTypes.get(originalType); + Map newMemberTypes = jsonMemberTypes.get(newType); + if (originalMemberTypes == null) return true; + if (originalMemberTypes.keySet().size() < newMemberTypes.keySet().size() + && newMemberTypes.keySet().containsAll(originalMemberTypes.keySet())) return true; + if (originalMemberTypes.keySet().size() > newMemberTypes.keySet().size()) return false; + if (!newMemberTypes.keySet().containsAll(originalMemberTypes.keySet())) return false; + for (String key: originalMemberTypes.keySet()) { + if (!originalMemberTypes.get(key).isAncestorOf(newMemberTypes.get(key))) return false; + } + return true; + } + } + return false; + } + + private interface IGroupExpressionsByResource { + public void groupForChannel(Channel ch); + } + + private interface IGroupExpressionsByVariable { + public void groupForChannel(Channel ch); + } + + private interface IGroupExpressionsByMessage { + public void groupForChannel(Channel rootCh, Channel ch); + } + + private static interface IExtractConstraintsOnExpressionsInTerm { + public void extractForChannel(Channel ch); + } + + private static interface IExtractConstraintsOnPathParametersAndResources { + public void extractForChannel(Channel ch); + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/models/algebra/Symbol.java b/AlgebraicDataflowArchitectureModel/src/models/algebra/Symbol.java index b358747..7bae391 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/algebra/Symbol.java +++ b/AlgebraicDataflowArchitectureModel/src/models/algebra/Symbol.java @@ -2,107 +2,80 @@ import java.util.List; +import models.algebra.Symbol.IImplGenerator; +import models.algebra.Symbol.Type; + public class Symbol { protected String name; - protected String implName; protected int arity = 0; // -1: variable number protected Type operatorType = Type.PREFIX; - protected Type implOperatorType = Type.PREFIX; protected Symbol[] inverses = null; protected models.algebra.Type[] signature = null; - protected int[] implParamOrder = null; - protected IImplGenerator generator = null; protected ICalculator calculator = null; + protected SymbolImpl symbolImpl = null; public Symbol(String name) { this.name = name; - this.implName = name; this.arity = 0; + this.symbolImpl = new SymbolImpl(name); } public Symbol(String name, int arity) { this.name = name; - this.implName = name; this.arity = arity; + this.symbolImpl = new SymbolImpl(name, arity); } public Symbol(String name, int arity, Type operatorType) { - this(name, arity); + this.name = name; + this.arity = arity; this.operatorType = operatorType; - this.implOperatorType = operatorType; + this.symbolImpl = new SymbolImpl(name, arity, operatorType); } public Symbol(String name, int arity, Type operatorType, String implName, Type implOperatorType) { this.name = name; - this.implName = implName; this.arity = arity; this.operatorType = operatorType; - this.implOperatorType = implOperatorType; + this.symbolImpl = new SymbolImpl(implName, arity, implOperatorType); } public Symbol(String name, int arity, Type operatorType, String implName, Type implOperatorType, int[] implParamOrder) { - this.name = name; - this.implName = implName; - this.arity = arity; - this.operatorType = operatorType; - this.implOperatorType = implOperatorType; - this.implParamOrder = implParamOrder; + this(name, arity, operatorType, implName, implOperatorType); + this.symbolImpl.setImplParamOrder(implParamOrder); } public Symbol(String name, int arity, Type operatorType, IImplGenerator generator) { - this.name = name; - this.implName = name; - this.arity = arity; - this.operatorType = operatorType; - this.generator = generator; - this.implOperatorType = Type.GENERATIVE; + this(name, arity, operatorType, name, Type.GENERATIVE); + this.symbolImpl.setGenerator(generator); } public Symbol(String name, int arity, Type operatorType, IImplGenerator generator, boolean bSideEffect) { - this.name = name; - this.implName = name; - this.arity = arity; - this.operatorType = operatorType; - this.generator = generator; - if (!bSideEffect) { - this.implOperatorType = Type.GENERATIVE; - } else { - this.implOperatorType = Type.GENERATIVE_WITH_SIDE_EFFECT; + this(name, arity, operatorType, name, Type.GENERATIVE); + this.symbolImpl.setGenerator(generator); + if (bSideEffect) { + this.symbolImpl.setImplOperatorType(Type.GENERATIVE_WITH_SIDE_EFFECT); } } public Symbol(String name, int arity, ICalculator calculator) { - this.name = name; - this.implName = name; - this.arity = arity; + this(name, arity); this.calculator = calculator; } public Symbol(String name, int arity, Type operatorType, ICalculator calculator) { - this.name = name; - this.implName = name; - this.arity = arity; - this.operatorType = operatorType; - this.implOperatorType = operatorType; + this(name, arity, operatorType, name, operatorType); this.calculator = calculator; } public Symbol(String name, int arity, Type operatorType, IImplGenerator generator, ICalculator calculator) { - this.name = name; - this.implName = name; - this.arity = arity; - this.operatorType = operatorType; - this.generator = generator; - this.implOperatorType = Type.GENERATIVE; + this(name, arity, operatorType, name, Type.GENERATIVE); this.calculator = calculator; + this.symbolImpl.setGenerator(generator); } public Symbol(String name, int arity, Type operatorType, String implName, Type implOperatorType, ICalculator calculator) { - this.name = name; - this.implName = implName; - this.arity = arity; - this.operatorType = operatorType; - this.implOperatorType = implOperatorType; + this(name, arity, operatorType, implName, implOperatorType); this.calculator = calculator; } @@ -120,7 +93,7 @@ public void changeName(String name) { this.name = name; - this.implName = name; + this.symbolImpl.setImplName(name); } public Type getOperatorType() { @@ -156,49 +129,49 @@ } public String getImplName() { - return implName; + return symbolImpl.getImplName(); } public void setImplName(String implName) { - this.implName = implName; + this.symbolImpl.setImplName(implName); } public Type getImplOperatorType() { - return implOperatorType; + return symbolImpl.getImplOperatorType(); } public boolean isImplInfix() { - return (implOperatorType == Type.INFIX); + return (symbolImpl.getImplOperatorType() == Type.INFIX); } public boolean isImplMethod() { - return (implOperatorType == Type.METHOD || implOperatorType == Type.METHOD_WITH_SIDE_EFFECT); + return (symbolImpl.getImplOperatorType() == Type.METHOD || symbolImpl.getImplOperatorType() == Type.METHOD_WITH_SIDE_EFFECT); } public boolean isImplLambda() { - return (implOperatorType == Type.LAMBDA || implOperatorType == Type.LAMBDA_WITH_SIDE_EFFECT); + return (symbolImpl.getImplOperatorType() == Type.LAMBDA || symbolImpl.getImplOperatorType() == Type.LAMBDA_WITH_SIDE_EFFECT); } public boolean isImplGenerative() { - return (implOperatorType == Type.GENERATIVE || implOperatorType == Type.GENERATIVE_WITH_SIDE_EFFECT); + return (symbolImpl.getImplOperatorType() == Type.GENERATIVE || symbolImpl.getImplOperatorType() == Type.GENERATIVE_WITH_SIDE_EFFECT); } public boolean isImplWithSideEffect() { - return (implOperatorType == Type.METHOD_WITH_SIDE_EFFECT - || implOperatorType == Type.LAMBDA_WITH_SIDE_EFFECT - || implOperatorType == Type.GENERATIVE_WITH_SIDE_EFFECT); + return (symbolImpl.getImplOperatorType() == Type.METHOD_WITH_SIDE_EFFECT + || symbolImpl.getImplOperatorType() == Type.LAMBDA_WITH_SIDE_EFFECT + || symbolImpl.getImplOperatorType() == Type.GENERATIVE_WITH_SIDE_EFFECT); } public void setImplOperatorType(Type implOperatorType) { - this.implOperatorType = implOperatorType; + this.symbolImpl.setImplOperatorType(implOperatorType); } public int[] getImplParamOrder() { - return implParamOrder; + return symbolImpl.getImplParamOrder(); } public void setGenerator(IImplGenerator generator) { - this.generator = generator; + this.symbolImpl.setGenerator(generator); } /** @@ -211,8 +184,8 @@ * @return the implementation */ public String generate(models.algebra.Type type, models.algebra.Type[] childrenTypes, String[] childrenImpl, String[] childrenSideEffects, String[] sideEffect) { - if (generator != null) { - return generator.generate(type, childrenTypes, childrenImpl, childrenSideEffects, sideEffect); + if (symbolImpl.getGenerator() != null) { + return symbolImpl.getGenerator().generate(type, childrenTypes, childrenImpl, childrenSideEffects, sideEffect); } return null; } @@ -243,7 +216,7 @@ } public String toImplementation() { - return implName; + return symbolImpl.getImplName(); } public enum Type { @@ -257,13 +230,78 @@ GENERATIVE_WITH_SIDE_EFFECT } + public static class SymbolImpl { + private String implName; + protected int implArity = 0; // -1: variable number + private Type implOperatorType; + private int[] implParamOrder; + private IImplGenerator generator; + + public SymbolImpl(String implName) { + this.implName = implName; + this.implArity = 0; + } + + public SymbolImpl(String implName, int implArity) { + this.implName = implName; + this.implArity = implArity; + } + + public SymbolImpl(String implName, int implArity, Type implOperatorType) { + this(implName, implArity); + this.implOperatorType = implOperatorType; + } + + public SymbolImpl(String implName, int implArity, Type implOperatorType, int[] implParamOrder) { + this(implName, implArity, implOperatorType); + this.implParamOrder = implParamOrder; + } + + public SymbolImpl(String implName, int implArity, Type implOperatorType, int[] implParamOrder, IImplGenerator generator) { + this(implName, implArity, implOperatorType, implParamOrder); + this.generator = generator; + } + + public String getImplName() { + return implName; + } + + public void setImplName(String implName) { + this.implName = implName; + } + + public Type getImplOperatorType() { + return implOperatorType; + } + + public void setImplOperatorType(Type implOperatorType) { + this.implOperatorType = implOperatorType; + } + + public int[] getImplParamOrder() { + return implParamOrder; + } + + public void setImplParamOrder(int[] implParamOrder) { + this.implParamOrder = implParamOrder; + } + + public IImplGenerator getGenerator() { + return generator; + } + + public void setGenerator(IImplGenerator generator) { + this.generator = generator; + } + } + public Memento createMemento() { - return new Memento(implName, implOperatorType); + return new Memento(symbolImpl.getImplName(), symbolImpl.getImplOperatorType()); } public void setMemento(Memento memento) { - this.implName = memento.implName; - this.implOperatorType = memento.implOperatorType; + this.symbolImpl.setImplName(memento.implName); + this.symbolImpl.setImplOperatorType(memento.implOperatorType); } public static class Memento { diff --git a/AlgebraicDataflowArchitectureModel/src/models/algebra/Type.java b/AlgebraicDataflowArchitectureModel/src/models/algebra/Type.java index 9e3eecb..d2c1780 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/algebra/Type.java +++ b/AlgebraicDataflowArchitectureModel/src/models/algebra/Type.java @@ -5,33 +5,35 @@ public class Type { private String typeName; - private String implementationTypeName; - private String interfaceTypeName; +// private String implementationTypeName; +// private String interfaceTypeName; private List parentTypes = new ArrayList<>(); + private ITypeImpl implementationType; + private ITypeImpl interfaceType; - public Type(String typeName, String implementationTypeName) { + public Type(String typeName, ITypeImpl implementationType) { this.typeName = typeName; - this.implementationTypeName = implementationTypeName; - this.interfaceTypeName = implementationTypeName; + this.implementationType = implementationType; + this.interfaceType = implementationType; } - public Type(String typeName, String implementationTypeName, String interfaceTypeName) { + public Type(String typeName, ITypeImpl implementationType, ITypeImpl interfaceType) { this.typeName = typeName; - this.implementationTypeName = implementationTypeName; - this.interfaceTypeName = interfaceTypeName; + this.implementationType = implementationType; + this.interfaceType = interfaceType; } - public Type(String typeName, String implementationTypeName, Type parentType) { + public Type(String typeName, ITypeImpl implementationType, Type parentType) { this.typeName = typeName; - this.implementationTypeName = implementationTypeName; - this.interfaceTypeName = implementationTypeName; + this.implementationType = implementationType; + this.interfaceType = implementationType; this.parentTypes.add(parentType); } - public Type(String typeName, String implementationTypeName, String interfaceTypeName, Type parentType) { + public Type(String typeName, ITypeImpl implementationType, ITypeImpl interfaceType, Type parentType) { this.typeName = typeName; - this.implementationTypeName = implementationTypeName; - this.interfaceTypeName = interfaceTypeName; + this.implementationType = implementationType; + this.interfaceType = interfaceType; this.parentTypes.add(parentType); } @@ -43,20 +45,20 @@ this.typeName = typeName; } - public String getImplementationTypeName() { - return implementationTypeName; + public ITypeImpl getImplementationType() { + return implementationType; } - public void setImplementationTypeName(String implementastionTypeName) { - this.implementationTypeName = implementastionTypeName; + public String getImplementationTypeName() { + return implementationType.toString(); + } + + public ITypeImpl getInterfaceType() { + return interfaceType; } public String getInterfaceTypeName() { - return interfaceTypeName; - } - - public void setInterfaceTypeName(String interfaceTypeName) { - this.interfaceTypeName = interfaceTypeName; + return interfaceType.toString(); } public List getParentTypes() { @@ -95,29 +97,32 @@ if (another == null) return false; if (!(another instanceof Type)) return false; if (!typeName.equals(((Type) another).typeName)) return false; - if (!implementationTypeName.equals(((Type) another).implementationTypeName)) return false; - if (!interfaceTypeName.equals(((Type) another).interfaceTypeName)) return false; + if (!implementationType.equals(((Type) another).implementationType)) return false; + if (!interfaceType.equals(((Type) another).interfaceType)) return false; return true; } + + public interface ITypeImpl { + } public Memento createMemento() { - return new Memento(implementationTypeName, interfaceTypeName, parentTypes); + return new Memento(implementationType, interfaceType, parentTypes); } public void setMemento(Memento memento) { - this.implementationTypeName = memento.implementationTypeName; - this.interfaceTypeName = memento.interfaceTypeName; + this.implementationType = memento.implementationType; + this.interfaceType = memento.interfaceType; this.parentTypes = memento.parentTypes; } public static class Memento { - private String implementationTypeName; - private String interfaceTypeName; + private ITypeImpl implementationType; + private ITypeImpl interfaceType; private List parentTypes; - public Memento(String implementationTypeName, String interfaceTypeName, List parentTypes) { - this.implementationTypeName = implementationTypeName; - this.interfaceTypeName = interfaceTypeName; + public Memento(ITypeImpl implementationType, ITypeImpl interfaceType, List parentTypes) { + this.implementationType = implementationType; + this.interfaceType = interfaceType; this.parentTypes = parentTypes; } } diff --git a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/DataConstraintModel.java b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/DataConstraintModel.java index 04685d9..33be5cc 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/DataConstraintModel.java +++ b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/DataConstraintModel.java @@ -10,6 +10,7 @@ import java.util.Map; import java.util.Stack; +import generators.JavaSpecific; import models.algebra.Constant; import models.algebra.Expression; import models.algebra.LambdaAbstraction; @@ -26,12 +27,12 @@ protected HashMap inputChannels = null; 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", typeInt); - public static final Type typeFloat = new Type("Float", "float", typeInt); - public static final Type typeDouble = new Type("Double", "double", typeFloat); - public static final Type typeBoolean = new Type("Bool", "boolean"); - public static final Type typeString = new Type("Str", "String") { + public static final Type typeInt = new Type("Int", new code.ast.PrimitiveType("int")); + public static final Type typeLong = new Type("Long", new code.ast.PrimitiveType("long"), typeInt); + public static final Type typeFloat = new Type("Float", new code.ast.PrimitiveType("float"), typeInt); + public static final Type typeDouble = new Type("Double", new code.ast.PrimitiveType("double"), typeFloat); + public static final Type typeBoolean = new Type("Bool", new code.ast.PrimitiveType("boolean")); + public static final Type typeString = new Type("Str", JavaSpecific.typeString) { public String valueToRepresentation(Object value) { if (value instanceof String) { return Parser.DOUBLE_QUOT + (String) value + Parser.DOUBLE_QUOT; @@ -45,16 +46,16 @@ return representation; } }; - public static final Type typeList = new Type("List", "ArrayList", "List"); - public static final Type typeListInt = new Type("List", "ArrayList<>", "List", typeList); - public static final Type typeListStr = new Type("List", "ArrayList<>", "List", typeList); - public static final Type typeTuple = new Type("Tuple", "AbstractMap.SimpleEntry", "Map.Entry"); - public static final Type typePair = new Type("Pair", "Pair", "Pair"); - public static final Type typePairInt = new Type("Pair", "Pair", "Pair", typePair); - public static final Type typePairStr = new Type("Pair", "Pair", "Pair", typePair); - public static final Type typePairDouble = new Type("Pair", "Pair", "Pair", typePair); - public static final Type typeMap = new Type("Map", "HashMap<>", "Map"); - public static final JsonType typeJson = new JsonType("Json", "HashMap<>", "Map"); + public static final Type typeList = new Type("List", JavaSpecific.typeArrayList, JavaSpecific.typeList); + public static final Type typeListInt = new Type("List", new code.ast.ParameterizedType(JavaSpecific.typeArrayList), new code.ast.ParameterizedType(JavaSpecific.typeList, List.of(JavaSpecific.typeInteger)), typeList); + public static final Type typeListStr = new Type("List", new code.ast.ParameterizedType(JavaSpecific.typeArrayList), new code.ast.ParameterizedType(JavaSpecific.typeList, List.of(JavaSpecific.typeString)), typeList); + public static final Type typeTuple = new Type("Tuple", new code.ast.SimpleType("AbstractMap.SimpleEntry"), new code.ast.SimpleType("Map.Entry")); + public static final Type typePair = new Type("Pair", new code.ast.SimpleType("Pair"), new code.ast.SimpleType("Pair")); + public static final Type typePairInt = new Type("Pair", new code.ast.ParameterizedType(JavaSpecific.typePair), new code.ast.ParameterizedType(JavaSpecific.typePair, List.of(JavaSpecific.typeInteger)), typePair); + public static final Type typePairStr = new Type("Pair", new code.ast.ParameterizedType(JavaSpecific.typePair), new code.ast.ParameterizedType(JavaSpecific.typePair, List.of(JavaSpecific.typeString)), typePair); + public static final Type typePairDouble = new Type("Pair", new code.ast.ParameterizedType(JavaSpecific.typePair), new code.ast.ParameterizedType(JavaSpecific.typePair, List.of(JavaSpecific.typeDouble)), typePair); + public static final Type typeMap = new Type("Map", new code.ast.ParameterizedType(JavaSpecific.typeHashMap), JavaSpecific.typeMap); + public static final JsonType typeJson = new JsonType("Json", new code.ast.ParameterizedType(JavaSpecific.typeHashMap), new code.ast.ParameterizedType(JavaSpecific.typeMap, List.of(JavaSpecific.typeString, JavaSpecific.typeObject))); public static final Symbol add = new Symbol(Parser.ADD, 2, Symbol.Type.INFIX, new Symbol.ICalculator() { @Override public Expression calculate(List args) { diff --git a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/JsonType.java b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/JsonType.java index 9f9e835..922351c 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/JsonType.java +++ b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/JsonType.java @@ -11,23 +11,23 @@ protected Map memberTypes = null; protected Type listOrMapElementType = null; - public JsonType(String typeName, String implementationTypeName) { - super(typeName, implementationTypeName); + public JsonType(String typeName, ITypeImpl implementationType) { + super(typeName, implementationType); memberTypes = new HashMap<>(); } - public JsonType(String typeName, String implementationTypeName, String interfaceTypeName) { - super(typeName, implementationTypeName, interfaceTypeName); + public JsonType(String typeName, ITypeImpl implementationType, ITypeImpl interfaceType) { + super(typeName, implementationType, interfaceType); memberTypes = new HashMap<>(); } - public JsonType(String typeName, String implementationTypeName, Type parentType) { - super(typeName, implementationTypeName, parentType); + public JsonType(String typeName, ITypeImpl implementationType, Type parentType) { + super(typeName, implementationType, parentType); memberTypes = new HashMap<>(); } - public JsonType(String typeName, String implementationTypeName, String interfaceTypeName, Type parentType) { - super(typeName, implementationTypeName, interfaceTypeName, parentType); + public JsonType(String typeName, ITypeImpl implementationType, ITypeImpl interfaceType, Type parentType) { + super(typeName, implementationType, interfaceType, parentType); memberTypes = new HashMap<>(); } diff --git a/AlgebraicDataflowArchitectureModel/src/parser/Parser.java b/AlgebraicDataflowArchitectureModel/src/parser/Parser.java index 951bcb0..8e2eb56 100644 --- a/AlgebraicDataflowArchitectureModel/src/parser/Parser.java +++ b/AlgebraicDataflowArchitectureModel/src/parser/Parser.java @@ -471,7 +471,7 @@ String typeName = stream.next(); Type type = model.getType(typeName); if (type == null) { - type = new Type(typeName, typeName); + type = new Type(typeName, new code.ast.SimpleType(typeName)); } term.setType(type); break; @@ -654,7 +654,7 @@ String typeName = stream.next(); Type type = model.getType(typeName); if (type == null) { - type = new Type(typeName, typeName); + type = new Type(typeName, new code.ast.SimpleType(typeName)); } var = new Variable(symbolName, type); } else { diff --git a/AlgebraicDataflowArchitectureModel/src/tests/ASTTest.java b/AlgebraicDataflowArchitectureModel/src/tests/ASTTest.java index 57015ee..14ced0d 100644 --- a/AlgebraicDataflowArchitectureModel/src/tests/ASTTest.java +++ b/AlgebraicDataflowArchitectureModel/src/tests/ASTTest.java @@ -36,7 +36,7 @@ forStatement.setBody(forBody); methodBody.addStatement(forStatement); - EnhancedForStatement efStmt = javaGen.getForStatementForCollection("s", "String", "list"); + EnhancedForStatement efStmt = javaGen.getForStatementForCollection(new VariableDeclaration(DataConstraintModel.typeString, "s"), "list"); Block efBody = new Block(); efBody.addStatement("System.out.println(s);"); efStmt.setBody(efBody); diff --git a/AlgebraicDataflowArchitectureModel/src/tests/InverseTest.java b/AlgebraicDataflowArchitectureModel/src/tests/InverseTest.java index 0d0efe1..44c9b6c 100644 --- a/AlgebraicDataflowArchitectureModel/src/tests/InverseTest.java +++ b/AlgebraicDataflowArchitectureModel/src/tests/InverseTest.java @@ -99,7 +99,7 @@ for (Position vPos: rhsVars4.keySet()) { Variable v = rhsVars4.get(vPos); if (x.getName().equals("x")) { - JsonType jsonType = new JsonType("Json", "HashMap<>", DataConstraintModel.typeJson); + JsonType jsonType = new JsonType("Json", new code.ast.ParameterizedType(new code.ast.SimpleType("HashMap")), DataConstraintModel.typeJson); jsonType.addMemberType("id", DataConstraintModel.typeInt); jsonType.addMemberType("name", DataConstraintModel.typeString); v.setType(jsonType); diff --git a/AlgebraicDataflowArchitectureModel/src/tests/JAXRSCodeGeneratorTest.java b/AlgebraicDataflowArchitectureModel/src/tests/JAXRSCodeGeneratorTest.java index b56b06d..75f22fd 100644 --- a/AlgebraicDataflowArchitectureModel/src/tests/JAXRSCodeGeneratorTest.java +++ b/AlgebraicDataflowArchitectureModel/src/tests/JAXRSCodeGeneratorTest.java @@ -31,6 +31,7 @@ import generators.JerseyCodeGenerator; import generators.JerseyMethodBodyGenerator; import generators.JerseySpecific; +import generators.TypeInference; import models.Edge; import models.dataFlowModel.*; import parser.*; @@ -1282,7 +1283,8 @@ } } } - TypeInference.infer(model); + TypeInference typeInference = new TypeInference(new JavaSpecific()); + typeInference.infer(model); DataTransferMethodAnalyzer.decideToStoreResourceStates(graph); // ArrayList codetree = JerseyMethodBodyGenerator.doGenerate(graph, model, JerseyCodeGenerator.doGenerate(graph, model)); ArrayList codetree = new CodeGeneratorFromDataFlowGraph().generateCode(model, graph, new JerseySpecific(), new JavaSpecific()); diff --git a/AlgebraicDataflowArchitectureModel/src/tests/JavaCodeGeneratorTest.java b/AlgebraicDataflowArchitectureModel/src/tests/JavaCodeGeneratorTest.java index 8128ce4..7d07402 100644 --- a/AlgebraicDataflowArchitectureModel/src/tests/JavaCodeGeneratorTest.java +++ b/AlgebraicDataflowArchitectureModel/src/tests/JavaCodeGeneratorTest.java @@ -26,6 +26,7 @@ import generators.JavaMethodBodyGenerator; import generators.JavaSpecific; import generators.StandaloneSpecific; +import generators.TypeInference; import models.Edge; import models.dataFlowModel.*; import parser.*; @@ -1436,7 +1437,8 @@ } } } - TypeInference.infer(model); + TypeInference typeInference = new TypeInference(new JavaSpecific()); + typeInference.infer(model); DataTransferMethodAnalyzer.decideToStoreResourceStates(graph); // ArrayList codetree = JavaMethodBodyGenerator.doGenerate(graph, model, JavaCodeGenerator.doGenerate(graph, model)); ArrayList codetree = new CodeGeneratorFromDataFlowGraph().generateCode(model, graph, new StandaloneSpecific(), new JavaSpecific()); diff --git a/AlgebraicDataflowArchitectureModel/src/tests/NativeAccessTest.java b/AlgebraicDataflowArchitectureModel/src/tests/NativeAccessTest.java index a91d089..63cda9e 100644 --- a/AlgebraicDataflowArchitectureModel/src/tests/NativeAccessTest.java +++ b/AlgebraicDataflowArchitectureModel/src/tests/NativeAccessTest.java @@ -2,7 +2,8 @@ import org.junit.Test; -import algorithms.TypeInference; +import generators.JavaSpecific; +import generators.TypeInference; import models.algebra.Expression; import models.algebra.InvalidMessage; import models.algebra.ParameterizedIdentifierIsFutureWork; @@ -68,7 +69,8 @@ textOut.getStateTransition().setNextStateExpression(nextStateOut); nativeOutputEventChannel.addChannelMemberAsInput(textOut); model.addChannel(nativeOutputEventChannel); - TypeInference.infer(model); + TypeInference typeInference = new TypeInference(new JavaSpecific()); + typeInference.infer(model); // Create simulator Simulator simulator = new Simulator(model);