diff --git a/AlgebraicDataflowArchitectureModel/models/CustomerOffice.model b/AlgebraicDataflowArchitectureModel/models/CustomerOffice.model index c587fb7..6c989ee 100644 --- a/AlgebraicDataflowArchitectureModel/models/CustomerOffice.model +++ b/AlgebraicDataflowArchitectureModel/models/CustomerOffice.model @@ -7,7 +7,7 @@ } channel C(uid:Str) { - in customers.{uid}.off(cid, sync(cid2, a2)) == cid2 - in companies.{cid2}.add(a1, sync(cid2, a2)) == a2 - out customers.{uid}.add(a3:Str, sync(cid2, a2)) == a2 + in customers.{uid}.off(cid, sync) == sync.id + in companies.{sync.id}.add(a1, sync) == sync.add + out customers.{uid}.add(a3:Str, sync) == sync.add } diff --git a/AlgebraicDataflowArchitectureModel/src/algorithms/TypeInference.java b/AlgebraicDataflowArchitectureModel/src/algorithms/TypeInference.java index 4479246..c81cdaf 100644 --- a/AlgebraicDataflowArchitectureModel/src/algorithms/TypeInference.java +++ b/AlgebraicDataflowArchitectureModel/src/algorithms/TypeInference.java @@ -13,6 +13,7 @@ import javax.xml.crypto.Data; import models.Node; +import models.algebra.Constant; import models.algebra.Expression; import models.algebra.Position; import models.algebra.Symbol; @@ -22,8 +23,10 @@ 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; @@ -43,6 +46,8 @@ 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); @@ -84,29 +89,48 @@ 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> resourceOwnership = 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> updateFromPathParams = new HashMap<>(); 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); @@ -132,22 +156,24 @@ ResourceHierarchy res = cm.getResource().getResourceHierarchy(); // 1.1 Group expressions by resources. - List sameResource = resources.get(res); - if (sameResource == null) { - sameResource = new ArrayList<>(); - resources.put(res, sameResource); + List identicalResources = resources.get(res); + if (identicalResources == null) { + identicalResources = new ArrayList<>(); + resources.put(res, identicalResources); } - sameResource.add(st.getCurStateExpression()); - if (st.getNextStateExpression() != null) sameResource.add(st.getNextStateExpression()); - expToResource.put(System.identityHashCode(st.getCurStateExpression()), sameResource); - if (st.getNextStateExpression() != null) expToResource.put(System.identityHashCode(st.getNextStateExpression()), sameResource); - Map updatedExps = getUpdateSet(updateFromResource, sameResource); + 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 : sameResource) { + for (Expression resExp : identicalResources) { if (resExp != exp) { if (resExp instanceof Variable && compareTypes(((Variable) resExp).getType(), expType)) { ((Variable) resExp).setType(expType); @@ -175,7 +201,7 @@ expType = getExpTypeIfUpdatable(resType, exp); if (expType != null) { res.setResourceStateType(expType); - for (Expression resExp : sameResource) { + for (Expression resExp : identicalResources) { if (resExp != exp) { if (resExp instanceof Variable && compareTypes(((Variable) resExp).getType(), expType)) { ((Variable) resExp).setType(expType); @@ -205,8 +231,22 @@ List allVariables = new ArrayList<>(); allVariables.addAll(st.getCurStateExpression().getVariables().values()); allVariables.addAll(st.getMessageExpression().getVariables().values()); - if (st.getNextStateExpression() != null) + if (st.getNextStateExpression() != null) { allVariables.addAll(st.getNextStateExpression().getVariables().values()); + } + for (Selector s: c.getSelectors()) { // 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) { @@ -344,7 +384,7 @@ if (symbol.equals(DataConstraintModel.cons) || symbol.equals(DataConstraintModel.set)) { // If the root symbol of the term is cons or set. List consExps = new ArrayList<>(); - consExps.add(t); + consExps.add(t); // list term updateExpressionBelonging(expToConsOrSet, t, consExps); if (symbol.equals(DataConstraintModel.cons)) { // If the root symbol of the term is cons. @@ -355,10 +395,10 @@ } else { // If the root symbol of the term is set. Expression e = t.getChildren().get(2); - consExps.add(e); + consExps.add(e); // list component updateExpressionBelonging(expToConsOrSet, e, consExps); e = t.getChildren().get(0); - consExps.add(e); + consExps.add(e); // list argument updateExpressionBelonging(expToConsOrSet, e, consExps); } Type newType = getExpTypeIfUpdatable(t.getType(), consExps.get(2)); @@ -411,9 +451,9 @@ // If the root symbol of the term is head or get. List consExps = new ArrayList<>(); Expression e = t.getChildren().get(0); - consExps.add(e); + consExps.add(e); // list argument updateExpressionBelonging(expToConsOrSet, e, consExps); - consExps.add(t); + consExps.add(t); // list's component updateExpressionBelonging(expToConsOrSet, t, consExps); consExps.add(null); Type listType = listTypes.get(t.getType()); @@ -447,11 +487,11 @@ } else if (symbol.equals(DataConstraintModel.tail)) { // If the root symbol of the term is tail. List consExps = new ArrayList<>(); - consExps.add(t); + consExps.add(t); // list term updateExpressionBelonging(expToConsOrSet, t, consExps); - consExps.add(null); + consExps.add(null); // list's component Expression e = t.getChildren().get(0); - consExps.add(e); + consExps.add(e); // list argument updateExpressionBelonging(expToConsOrSet, e, consExps); Type newType = getExpTypeIfUpdatable(t.getType(), consExps.get(2)); if (newType != null) { @@ -483,26 +523,27 @@ } else if (symbol.equals(DataConstraintModel.tuple)) { // If the root symbol of the term is tuple. List tupleExps = new ArrayList<>(); - List argsTypeList = new ArrayList<>(); - tupleExps.add(t); + List newArgTypesList = new ArrayList<>(); + tupleExps.add(t); // tuple term updateExpressionBelonging(expToTuple, t, tupleExps); for (Expression e : t.getChildren()) { - tupleExps.add(e); + tupleExps.add(e); // tuple's component updateExpressionBelonging(expToTuple, e, tupleExps); if (e instanceof Variable) { - argsTypeList.add(((Variable) e).getType()); + newArgTypesList.add(((Variable) e).getType()); } else if (e instanceof Term) { - argsTypeList.add(((Term) e).getType()); + newArgTypesList.add(((Term) e).getType()); } else { - argsTypeList.add(null); + newArgTypesList.add(null); } } if (t.getType() == DataConstraintModel.typeTuple) { - Type newTupleType = tupleTypes.get(argsTypeList); + Type newTupleType = tupleTypes.get(newArgTypesList); if (newTupleType == null) { // Create new tuple type; - newTupleType = createNewTupleType(argsTypeList, DataConstraintModel.typeTuple); + 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); @@ -511,22 +552,22 @@ } else if (symbol.equals(DataConstraintModel.pair)) { // If the root symbol of the term is pair. List pairExps = new ArrayList<>(); - pairExps.add(t); + pairExps.add(t); // pair updateExpressionBelonging(expToPair, t, pairExps); if (t.getType() == DataConstraintModel.typePair) { for (Expression e : t.getChildren()) { - pairExps.add(e); + pairExps.add(e); // left/right updateExpressionBelonging(expToPair, e, pairExps); - Type argType = null; + Type newArgType = null; if (e instanceof Variable) { - argType = (((Variable) e).getType()); + newArgType = (((Variable) e).getType()); } else if (e instanceof Term) { - argType = (((Term) e).getType()); + newArgType = (((Term) e).getType()); } - if (argType != null) { - Type newPairType = pairTypes.get(argType); + if (newArgType != null) { + Type newPairType = pairTypes.get(newArgType); if (newPairType != null) { t.setType(newPairType); Map updateExps = getUpdateSet(updateFromPair, pairExps); @@ -541,11 +582,11 @@ // If the root symbol of the term is fst. List tupleExps = new ArrayList<>(); Expression arg = t.getChildren().get(0); - tupleExps.add(arg); + tupleExps.add(arg); // tuple argument updateExpressionBelonging(expToTuple, arg, tupleExps); - tupleExps.add(t); + tupleExps.add(t); // first component updateExpressionBelonging(expToTuple, t, tupleExps); - tupleExps.add(null); + tupleExps.add(null); // second component Type argType = null; if (arg instanceof Variable) { argType = ((Variable) arg).getType(); @@ -554,16 +595,17 @@ } Type newTupleType = DataConstraintModel.typeTuple; if (argType == DataConstraintModel.typeTuple && t.getType() != null) { - List compTypeList = new ArrayList<>(); - compTypeList.add(t.getType()); - compTypeList.add(null); - newTupleType = tupleTypes.get(compTypeList); + List newCompTypeList = new ArrayList<>(); + newCompTypeList.add(t.getType()); + newCompTypeList.add(null); + newTupleType = tupleTypes.get(newCompTypeList); if (newTupleType == null) { // Create new tuple type; - newTupleType = createNewTupleType(compTypeList, DataConstraintModel.typeTuple); + 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; @@ -579,10 +621,10 @@ // If the root symbol of the term is snd. List tupleExps = new ArrayList<>(); Expression arg = t.getChildren().get(0); - tupleExps.add(arg); + tupleExps.add(arg); // tuple argument updateExpressionBelonging(expToTuple, arg, tupleExps); - tupleExps.add(null); - tupleExps.add(t); + tupleExps.add(null); // first component + tupleExps.add(t); // second component updateExpressionBelonging(expToTuple, t, tupleExps); Type argType = null; if (arg instanceof Variable) { @@ -592,27 +634,28 @@ } Type newTupleType = DataConstraintModel.typeTuple; if (argType == DataConstraintModel.typeTuple && t.getType() != null) { - List compTypeList = new ArrayList<>(); - compTypeList.add(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) { - compTypeList.add(t2); + newCompTypeList.add(t2); } } else { - compTypeList.add(t.getType()); + newCompTypeList.add(t.getType()); } } else { - compTypeList.add(t.getType()); + newCompTypeList.add(t.getType()); } - newTupleType = tupleTypes.get(compTypeList); + newTupleType = tupleTypes.get(newCompTypeList); if (newTupleType == null) { // Create new tuple type; - newTupleType = createNewTupleType(compTypeList, DataConstraintModel.typeTuple); + 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; @@ -628,11 +671,11 @@ // If the root symbol of the term is left. List pairExps = new ArrayList<>(); Expression arg = t.getChildren().get(0); - pairExps.add(arg); + pairExps.add(arg); // pair updateExpressionBelonging(expToPair, arg, pairExps); - pairExps.add(t); + pairExps.add(t); // left updateExpressionBelonging(expToPair, t, pairExps); - pairExps.add(null); + pairExps.add(null); // right Type argType = null; if (arg instanceof Variable) { argType = ((Variable) arg).getType(); @@ -641,13 +684,13 @@ } Type newPairType = DataConstraintModel.typePair; if (argType == DataConstraintModel.typePair && t.getType() != null) { - List compTypeList = new ArrayList<>(); - compTypeList.add(t.getType()); - compTypeList.add(null); - newPairType = pairTypes.get(compTypeList); + List newCompTypeList = new ArrayList<>(); + newCompTypeList.add(t.getType()); + newCompTypeList.add(null); + newPairType = pairTypes.get(newCompTypeList); if (newPairType == null) { // Create new tuple type; - newPairType = createNewTupleType(compTypeList, DataConstraintModel.typePair); + newPairType = createNewTupleType(newCompTypeList, DataConstraintModel.typePair); } } if (argType != newPairType && newPairType != null) { @@ -666,10 +709,10 @@ // If the root symbol of the term is right. List pairExps = new ArrayList<>(); Expression arg = t.getChildren().get(0); - pairExps.add(arg); + pairExps.add(arg); // pair updateExpressionBelonging(expToPair, arg, pairExps); - pairExps.add(null); - pairExps.add(t); + pairExps.add(null); // left + pairExps.add(t); // right updateExpressionBelonging(expToPair, t, pairExps); Type argType = null; if (arg instanceof Variable) { @@ -679,13 +722,13 @@ } Type newPairType = DataConstraintModel.typePair; if (argType == DataConstraintModel.typePair && t.getType() != null) { - List compTypeList = new ArrayList<>(); - compTypeList.add(null); - compTypeList.add(t.getType()); - newPairType = pairTypes.get(compTypeList); + List newCompTypeList = new ArrayList<>(); + newCompTypeList.add(null); + newCompTypeList.add(t.getType()); + newPairType = pairTypes.get(newCompTypeList); if (newPairType == null) { // Create new tuple type; - newPairType = createNewTupleType(compTypeList, DataConstraintModel.typePair); + newPairType = createNewTupleType(newCompTypeList, DataConstraintModel.typePair); } } if (argType != newPairType && newPairType != null) { @@ -717,21 +760,22 @@ } else if (arg1 instanceof Term) { arg1Type = ((Term) arg1).getType(); } - List compTypeList = new ArrayList<>(); + List newCompTypeList = new ArrayList<>(); if (arg2 instanceof Variable) { - compTypeList.add(((Variable) arg2).getType()); + newCompTypeList.add(((Variable) arg2).getType()); } else if (arg2 instanceof Term) { - compTypeList.add(((Term) arg2).getType()); + newCompTypeList.add(((Term) arg2).getType()); } else { - compTypeList.add(null); + newCompTypeList.add(null); } - compTypeList.add(t.getType()); + newCompTypeList.add(t.getType()); if (arg1Type == DataConstraintModel.typeMap || arg1Type == null) { - Type newMapType = mapTypes.get(compTypeList); + Type newMapType = mapTypes.get(newCompTypeList); if (newMapType == null) { // Create new tuple type; - newMapType = createNewMapType(compTypeList, DataConstraintModel.typeMap); + 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; @@ -758,33 +802,186 @@ mapExps.add(arg0); updateExpressionBelonging(expToMap, arg0, mapExps); Type termType = t.getType(); - List compTypeList = new ArrayList<>(); + List newCompTypeList = new ArrayList<>(); if (arg1 instanceof Variable) { - compTypeList.add(((Variable) arg1).getType()); + newCompTypeList.add(((Variable) arg1).getType()); } else if (arg1 instanceof Term) { - compTypeList.add(((Term) arg1).getType()); + newCompTypeList.add(((Term) arg1).getType()); } else { - compTypeList.add(null); + newCompTypeList.add(null); } if (arg2 instanceof Variable) { - compTypeList.add(((Variable) arg2).getType()); + newCompTypeList.add(((Variable) arg2).getType()); } else if (arg2 instanceof Term) { - compTypeList.add(((Term) arg2).getType()); + newCompTypeList.add(((Term) arg2).getType()); } else { - compTypeList.add(null); + newCompTypeList.add(null); } if (termType == DataConstraintModel.typeMap || termType == null) { - Type newMapType = mapTypes.get(compTypeList); + Type newMapType = mapTypes.get(newCompTypeList); if (newMapType == null) { // Create new tuple type; - newMapType = createNewMapType(compTypeList, DataConstraintModel.typeMap); + newMapType = createNewMapType(newCompTypeList, DataConstraintModel.typeMap); } + // Update the type of the map term and record the updated expression. t.setType(newMapType); termType = newMapType; Map updateExps = getUpdateSet(updateFromMap, mapExps); updateExps.put(System.identityHashCode(t), t); } 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) { + // 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) { + // 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) { + // 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); @@ -925,12 +1122,65 @@ variables.put(System.identityHashCode(consExps), condType); } } + + // 1.5 Extract constraints on path parameters and resources. + 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(); + } + } + } + + // 1.6 Extract constraints on resource hierarchies. + for (ResourceHierarchy res: model.getResourceHierarchies()) { + if (res.getParent() != null) { + Set children = resourceOwnership.get(res.getParent()); + if (children == null) { + children = new HashSet<>(); + resourceOwnership.put(res.getParent(), children); + } + children.add(res); + } + 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) { + || 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(); @@ -944,6 +1194,8 @@ 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) { @@ -953,13 +1205,15 @@ updateFromVariable.remove(variableKey); for (int i : variableValue.keySet()) { Expression var = variableValue.get(i); - updateResourceTypes(var, resources, expToResource, updateFromResource); + 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) { @@ -969,12 +1223,14 @@ updateFromMessage.remove(messageKey); for (int i : messageValue.keySet()) { Expression mesExp = messageValue.get(i); - updateResourceTypes(mesExp, resources, expToResource, updateFromResource); + 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) { @@ -984,13 +1240,14 @@ updateFromConsOrSet.remove(consKey); for (int i : consValue.keySet()) { Expression consExp = consValue.get(i); - updateResourceTypes(consExp, resources, expToResource, updateFromResource); + 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) { @@ -1000,13 +1257,14 @@ updateFromTuple.remove(tupleKey); for (int i : tupleValue.keySet()) { Expression tupleExp = tupleValue.get(i); - updateResourceTypes(tupleExp, resources, expToResource, updateFromResource); + 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) { @@ -1016,13 +1274,14 @@ updateFromPair.remove(pairKey); for (int i : pairValue.keySet()) { Expression pairExp = pairValue.get(i); - updateResourceTypes(pairExp, resources, expToResource, updateFromResource); + 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) { @@ -1032,15 +1291,38 @@ updateFromMap.remove(mapKey); for (int i : mapValue.keySet()) { Expression mapExp = mapValue.get(i); - updateResourceTypes(mapExp, resources, expToResource, updateFromResource); + 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, resourceOwnership, expToResource, updateFromResource, updateFromResourceOwnership); + } } } @@ -1057,18 +1339,20 @@ } } - private static void updateResourceTypes(Expression exp, Map> resources, - Map> expToResource, Map> updateFromResource) { - List sameResource = expToResource.get(System.identityHashCode(exp)); - if (sameResource == null) return; - for (ResourceHierarchy res : resources.keySet()) { - if (resources.get(res) == sameResource) { + 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); - Map updateExps = getUpdateSet(updateFromResource, sameResource); - for (Expression resExp : sameResource) { + 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); @@ -1083,6 +1367,146 @@ } } } + + 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> resourceOwnership, Map> expToResource, + Map> updateFromResource, Set updateFromResourceOwnership) { + for (ResourceHierarchy parent: resourceOwnership.keySet()) { + Type resType = res.getResourceStateType(); + Set children = resourceOwnership.get(parent); + 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) { @@ -1168,6 +1592,7 @@ 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); @@ -1192,6 +1617,7 @@ } 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); @@ -1217,6 +1643,7 @@ } break; case 2: + // exp is a list itself. listType = consOrSet.get(System.identityHashCode(consOrSetComponentGroup)); expType = getExpTypeIfUpdatable(listType, exp); if (expType != null) { @@ -1246,6 +1673,7 @@ 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) { @@ -1313,6 +1741,7 @@ } } } else { + // exp is a tuple's component. Type tupleType = tuple.get(System.identityHashCode(tupleComponentGroup)); List componentTypes = tupleComponentTypes.get(tupleType); boolean updated = false; @@ -1383,6 +1812,7 @@ 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) { @@ -1406,6 +1836,7 @@ } } } else { + // exp is a pair's component. Type pairType = pair.get(System.identityHashCode(pairComponentGroup)); Type compType = pairComponentTypes.get(pairType); Type newCompType = getExpTypeIfUpdatable(compType, exp); @@ -1436,6 +1867,7 @@ 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) { @@ -1479,6 +1911,7 @@ } } } 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); @@ -1517,6 +1950,114 @@ } } + + 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)); + 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(); + } + 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()); @@ -1599,9 +2140,39 @@ return newMapType; } - private static List getChildrenTypes(Type parentType, Set componentTypes) { + 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 : componentTypes) { + for (Type childType : allTypes) { if (childType.getParentTypes().contains(parentType)) { childrenTypes.add(childType); } @@ -1683,6 +2254,7 @@ 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); @@ -1690,6 +2262,7 @@ } 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); @@ -1707,6 +2280,19 @@ 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; } diff --git a/AlgebraicDataflowArchitectureModel/src/application/editor/DataTransferModelingCellEditor.java b/AlgebraicDataflowArchitectureModel/src/application/editor/DataTransferModelingCellEditor.java index b4d81a6..2d8dfe3 100644 --- a/AlgebraicDataflowArchitectureModel/src/application/editor/DataTransferModelingCellEditor.java +++ b/AlgebraicDataflowArchitectureModel/src/application/editor/DataTransferModelingCellEditor.java @@ -31,6 +31,7 @@ import parser.Parser; import parser.Parser.TokenStream; import parser.exceptions.ExpectedRightBracket; +import parser.exceptions.WrongJsonExpression; public class DataTransferModelingCellEditor implements mxICellEditor { public int DEFAULT_MIN_WIDTH = 70; @@ -123,7 +124,7 @@ Expression exp = parser.parseTerm(stream, editor.getModel()); ((FormulaChannel) ch).setFormula(formula); ((FormulaChannel) ch).setFormulaTerm(exp); - } catch (ExpectedRightBracket e) { + } catch (ExpectedRightBracket | WrongJsonExpression e) { e.printStackTrace(); } } diff --git a/AlgebraicDataflowArchitectureModel/src/application/editor/Editor.java b/AlgebraicDataflowArchitectureModel/src/application/editor/Editor.java index c81b30b..0264f06 100644 --- a/AlgebraicDataflowArchitectureModel/src/application/editor/Editor.java +++ b/AlgebraicDataflowArchitectureModel/src/application/editor/Editor.java @@ -66,6 +66,7 @@ import parser.exceptions.ExpectedResource; import parser.exceptions.ExpectedRightBracket; import parser.exceptions.ExpectedStateTransition; +import parser.exceptions.WrongJsonExpression; import parser.exceptions.WrongLHSExpression; import parser.exceptions.WrongRHSExpression; import parser.exceptions.ExpectedRightCurlyBracket; @@ -202,7 +203,7 @@ | ExpectedStateTransition | ExpectedEquals | ExpectedRHSExpression | WrongLHSExpression | WrongRHSExpression | ExpectedRightBracket | ExpectedAssignment | ExpectedModel | ExpectedGeometry | ExpectedNode | ExpectedResource | ExpectedFormulaChannel | ExpectedIoChannel - | ExpectedRightCurlyBracket | WrongPathExpression e) { + | ExpectedRightCurlyBracket | WrongPathExpression | WrongJsonExpression e) { e.printStackTrace(); } } @@ -238,7 +239,7 @@ return model; } catch (ExpectedChannel | ExpectedChannelName | ExpectedLeftCurlyBracket | ExpectedInOrOutOrRefOrSubKeyword | ExpectedStateTransition | ExpectedEquals | ExpectedRHSExpression | WrongLHSExpression - | WrongRHSExpression | ExpectedRightBracket | ExpectedAssignment | ExpectedRightCurlyBracket | WrongPathExpression e) { + | WrongRHSExpression | ExpectedRightBracket | ExpectedAssignment | ExpectedRightCurlyBracket | WrongPathExpression | WrongJsonExpression e) { e.printStackTrace(); } } catch (FileNotFoundException e) { @@ -513,7 +514,7 @@ Expression exp = parser.parseTerm(stream, getModel()); resourcePath = new ResourcePath(parentPath, exp); getModel().addResourcePath(resourcePath); - } catch (ExpectedRightBracket e) { + } catch (ExpectedRightBracket | WrongJsonExpression e) { e.printStackTrace(); return null; } @@ -703,7 +704,7 @@ resetDataFlowGraph(); } catch (ExpectedRightBracket | ExpectedChannel | ExpectedChannelName | ExpectedLeftCurlyBracket | ExpectedInOrOutOrRefOrSubKeyword | ExpectedStateTransition | ExpectedEquals | ExpectedRHSExpression - | WrongLHSExpression | WrongRHSExpression | ExpectedAssignment | ExpectedRightCurlyBracket | WrongPathExpression e) { + | WrongLHSExpression | WrongRHSExpression | ExpectedAssignment | ExpectedRightCurlyBracket | WrongPathExpression | WrongJsonExpression e) { e.printStackTrace(); } } diff --git a/AlgebraicDataflowArchitectureModel/src/models/algebra/Type.java b/AlgebraicDataflowArchitectureModel/src/models/algebra/Type.java index 50b0285..eb827bf 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/algebra/Type.java +++ b/AlgebraicDataflowArchitectureModel/src/models/algebra/Type.java @@ -9,28 +9,28 @@ private String interfaceTypeName; private List parentTypes = new ArrayList<>(); - public Type(String typeName, String implementastionTypeName) { + public Type(String typeName, String implementationTypeName) { this.typeName = typeName; - this.implementationTypeName = implementastionTypeName; - this.interfaceTypeName = implementastionTypeName; + this.implementationTypeName = implementationTypeName; + this.interfaceTypeName = implementationTypeName; } - public Type(String typeName, String implementastionTypeName, String interfaceTypeName) { + public Type(String typeName, String implementationTypeName, String interfaceTypeName) { this.typeName = typeName; - this.implementationTypeName = implementastionTypeName; + this.implementationTypeName = implementationTypeName; this.interfaceTypeName = interfaceTypeName; } - public Type(String typeName, String implementastionTypeName, Type parentType) { + public Type(String typeName, String implementationTypeName, Type parentType) { this.typeName = typeName; - this.implementationTypeName = implementastionTypeName; - this.interfaceTypeName = implementastionTypeName; + this.implementationTypeName = implementationTypeName; + this.interfaceTypeName = implementationTypeName; this.parentTypes.add(parentType); } - public Type(String typeName, String implementastionTypeName, String interfaceTypeName, Type parentType) { + public Type(String typeName, String implementationTypeName, String interfaceTypeName, Type parentType) { this.typeName = typeName; - this.implementationTypeName = implementastionTypeName; + this.implementationTypeName = implementationTypeName; this.interfaceTypeName = interfaceTypeName; this.parentTypes.add(parentType); } diff --git a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/DataConstraintModel.java b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/DataConstraintModel.java index 79137dc..5c8d782 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/DataConstraintModel.java +++ b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/DataConstraintModel.java @@ -35,8 +35,9 @@ 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 Symbol add = new Symbol(Parser.ADD, 2, Symbol.Type.INFIX); - public static final Symbol mul = new Symbol(Parser.MUL, 2, Symbol.Type.INFIX);; + public static final Symbol mul = new Symbol(Parser.MUL, 2, Symbol.Type.INFIX); public static final Symbol sub = new Symbol(Parser.SUB, 2, Symbol.Type.INFIX); public static final Symbol div = new Symbol(Parser.DIV, 2, Symbol.Type.INFIX); public static final Symbol minus = new Symbol(Parser.MINUS, 1); @@ -150,6 +151,10 @@ return temp; } }); + public static final Symbol json = new Symbol("json", 0, Symbol.Type.PREFIX, "new HashMap<>", Symbol.Type.METHOD); + public static final Symbol addMember = new Symbol("addMember", 3, Symbol.Type.PREFIX, "put", Symbol.Type.METHOD); + public static final Symbol dot = new Symbol(Parser.DOT, 2, Symbol.Type.INFIX, "get", Symbol.Type.METHOD); + public static final Symbol dotParam = new Symbol(Parser.DOT, 2, Symbol.Type.INFIX, "get", Symbol.Type.METHOD); public static final Symbol pi = new Symbol("PI", 0, Symbol.Type.PREFIX, "Math.PI", Symbol.Type.PREFIX); public static final Symbol E = new Symbol("E", 0, Symbol.Type.PREFIX, "Math.E", Symbol.Type.PREFIX); public static final Symbol sqrt = new Symbol("sqrt", 1, Symbol.Type.PREFIX, "Math.sqrt", Symbol.Type.PREFIX); @@ -201,6 +206,10 @@ snd.setInverses(new Symbol[] {new LambdaAbstraction(new Variable("y"), new Term(tuple, new Expression[] {new Variable("x"), new Variable("y")}))}); insert.setSignature(new Type[] {typeMap, typeMap, null, null}); lookup.setSignature(new Type[] {null, typeMap, null}); + json.setSignature(new Type[] {typeJson}); + addMember.setSignature(new Type[] {typeJson, typeJson, typeString, null}); + dot.setSignature(new Type[] {null, typeJson, typeString}); + dotParam.setSignature(new Type[] {null, null, null}); pi.setSignature(new Type[] {typeDouble}); E.setSignature(new Type[] {typeDouble}); sqrt.setSignature(new Type[] {typeDouble, typeDouble}); @@ -237,6 +246,7 @@ addType(typePair); addType(typeTuple); addType(typeMap); + addType(typeJson); symbols = new HashMap<>(); addSymbol(add); addSymbol(mul); @@ -273,6 +283,10 @@ addSymbol(snd); addSymbol(insert); addSymbol(lookup); + addSymbol(json); + addSymbol(addMember); + addSymbol(dot); + addSymbol(dotParam); addSymbol(pi); addSymbol(E); addSymbol(sqrt); diff --git a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/JsonAccessor.java b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/JsonAccessor.java new file mode 100644 index 0000000..a033e28 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/JsonAccessor.java @@ -0,0 +1,148 @@ +package models.dataConstraintModel; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import models.algebra.Constant; +import models.algebra.Expression; +import models.algebra.LambdaAbstraction; +import models.algebra.Position; +import models.algebra.Symbol; +import models.algebra.Term; +import models.algebra.Type; +import models.algebra.Variable; + +public class JsonAccessor extends Term { + + public JsonAccessor(Symbol symbol) { + super(symbol); + } + + public Type getType() { + if (symbol.equals(DataConstraintModel.dotParam)) { + Type valueType = null; + if (getChild(1) instanceof Term) { + valueType = ((Term) getChild(1)).getType(); + } else if (getChild(1) instanceof Variable) { + valueType = ((Variable) getChild(1)).getType(); + } + if (valueType != null) { + if (valueType.equals(DataConstraintModel.typeInt)) { + return DataConstraintModel.typeList; + } else if (valueType.equals(DataConstraintModel.typeString)) { + return DataConstraintModel.typeMap; + } + } + } + return super.getType(); + } + + + @Override + public Expression getInverseMap(Expression outputValue, Position targetPos) { + if (targetPos.isEmpty()) return outputValue; + targetPos = (Position) targetPos.clone(); + int i = targetPos.removeHeadOrder(); + Symbol[] inverseSymbols = symbol.getInverses(); + if (i == 0) { + if (symbol.equals(DataConstraintModel.dot) && getChildren().size() >= 2) { + // this term is `json.key`. + Expression expJson = getChild(0); + Expression expKey = getChild(1); + JsonType jsonType = null; + if (expJson instanceof Variable) { + jsonType = (JsonType) ((Variable) expJson).getType(); + } else if (expJson instanceof Term) { + jsonType = (JsonType) ((Term) expJson).getType(); + } + String keyName = null; + if (expKey instanceof Constant) { + keyName = ((Constant) expKey).getSymbol().getName(); + Term jsonTerm = new Constant(DataConstraintModel.json); + int v = 1; + Map vars = new HashMap<>(); + Set keySet = new HashSet<>(); + if (jsonType == null || jsonType == DataConstraintModel.typeJson) { + keySet.add(keyName); + } else { + keySet.addAll(jsonType.getKeys()); + } + for (String key: keySet) { + Term addMemberTerm = new Term(DataConstraintModel.addMember); // addMember(jsonTerm, key, v) + addMemberTerm.addChild(jsonTerm); + addMemberTerm.addChild(new Constant(key)); + Variable var = new Variable("v" + v); + addMemberTerm.addChild(var); + vars.put(key, var); + jsonTerm = addMemberTerm; + v++; + } + Variable var = vars.get(keyName); + LambdaAbstraction lambdaAbstraction = new LambdaAbstraction(var, jsonTerm); // v -> addMember(jsonTerm, key, v) + inverseSymbols = new Symbol[] { lambdaAbstraction }; + } + } else if (symbol.equals(DataConstraintModel.dotParam) && getChildren().size() >= 2) { + // this term is `json.{param}`. + Expression expListOrMap = getChild(0); + Expression expKey = getChild(1); + JsonType jsonType = null; + if (expListOrMap instanceof Variable) { + jsonType = (JsonType) ((Variable) expListOrMap).getType(); + } else if (expListOrMap instanceof Term) { + jsonType = (JsonType) ((Term) expListOrMap).getType(); + } + Type keyType = null; + if (expKey instanceof Variable) { + keyType = (JsonType) ((Variable) expKey).getType(); + } else if (expKey instanceof Term) { + keyType = (JsonType) ((Term) expKey).getType(); + } + if (jsonType != null && keyType != null) { + if (DataConstraintModel.typeList.isAncestorOf(jsonType) || keyType.equals(DataConstraintModel.typeInt)) { + Term setElementTerm = new Term(DataConstraintModel.set); // set(list, idx, v) + setElementTerm.addChild(new Constant(DataConstraintModel.nil)); + setElementTerm.addChild(expKey); + Variable var = new Variable("v"); + setElementTerm.addChild(var); + LambdaAbstraction lambdaAbstraction = new LambdaAbstraction(var, setElementTerm); // v -> set(list, idx, v) + inverseSymbols = new Symbol[] { lambdaAbstraction }; + } else if (DataConstraintModel.typeMap.isAncestorOf(jsonType) || keyType.equals(DataConstraintModel.typeString)) { + Term insertEntryTerm = new Term(DataConstraintModel.insert); // insert(map, key, v) + insertEntryTerm.addChild(new Constant(DataConstraintModel.nil)); + insertEntryTerm.addChild(expKey); + Variable var = new Variable("v"); + insertEntryTerm.addChild(var); + LambdaAbstraction lambdaAbstraction = new LambdaAbstraction(var, insertEntryTerm); // v -> insert(map, key, v) + inverseSymbols = new Symbol[] { lambdaAbstraction }; + } + } + } + } + if (inverseSymbols == null || i >= inverseSymbols.length || inverseSymbols[i] == null) return null; + Term inverseMap = new Term(inverseSymbols[i]); + inverseMap.addChild(outputValue); + for (int n = 0; n < inverseSymbols[i].getArity(); n++) { + if (n != i) { + inverseMap.addChild(children.get(n)); + } + } + return children.get(i).getInverseMap(inverseMap, targetPos); + } + + public String toString() { + if (symbol.equals(DataConstraintModel.dotParam)) { + return children.get(0).toString() + symbol.toString() + "{" + children.get(1).toString() + "}"; + } + return super.toString(); + } + + public String toImplementation(String[] sideEffects) { + if (symbol.equals(DataConstraintModel.dotParam)) { + return children.get(0).toImplementation(sideEffects) + symbol.toImplementation() + "{" + children.get(1).toImplementation(sideEffects) + "}"; + } + return super.toImplementation(sideEffects); + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/JsonType.java b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/JsonType.java new file mode 100644 index 0000000..9f9e835 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/JsonType.java @@ -0,0 +1,65 @@ +package models.dataConstraintModel; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import models.algebra.Type; + +public class JsonType extends Type { + protected boolean isListOrMap = false; + protected Map memberTypes = null; + protected Type listOrMapElementType = null; + + public JsonType(String typeName, String implementationTypeName) { + super(typeName, implementationTypeName); + memberTypes = new HashMap<>(); + } + + public JsonType(String typeName, String implementationTypeName, String interfaceTypeName) { + super(typeName, implementationTypeName, interfaceTypeName); + memberTypes = new HashMap<>(); + } + + public JsonType(String typeName, String implementationTypeName, Type parentType) { + super(typeName, implementationTypeName, parentType); + memberTypes = new HashMap<>(); + } + + public JsonType(String typeName, String implementationTypeName, String interfaceTypeName, Type parentType) { + super(typeName, implementationTypeName, interfaceTypeName, parentType); + memberTypes = new HashMap<>(); + } + + public Map getMemberTypes() { + return memberTypes; + } + + public Type getMemberType(String key) { + return memberTypes.get(key); + } + + public Set getKeys() { + return memberTypes.keySet(); + } + + public void addMemberType(String key, Type valueType) { + memberTypes.put(key, valueType); + } + +// public boolean isListOrMap() { +// return isListOrMap; +// } +// +// public void setListOrMap(boolean isListOrMap) { +// this.isListOrMap = isListOrMap; +// } + + public Type getElementType() { + return listOrMapElementType; + } + + public void setElementType(Type listElementType) { + this.listOrMapElementType = listElementType; + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/ResourceHierarchy.java b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/ResourceHierarchy.java index 7e0ca88..f3a89ce 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/ResourceHierarchy.java +++ b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/ResourceHierarchy.java @@ -5,6 +5,7 @@ import models.algebra.Expression; import models.algebra.Term; import models.algebra.Type; +import models.algebra.Variable; public class ResourceHierarchy { private ResourceHierarchy parent = null; @@ -31,6 +32,9 @@ this.parent = parent; this.resourceName = resourceName; this.numParameters = 0; + if (parent != null && parent.getResourceStateType() == null) { + parent.setResourceStateType(DataConstraintModel.typeJson); + } } public ResourceHierarchy(ResourceHierarchy parent, String resourceName, Type resourceStateType) { @@ -38,6 +42,9 @@ this.resourceName = resourceName; this.numParameters = 0; this.resourceStateType = resourceStateType; + if (parent != null && parent.getResourceStateType() == null) { + parent.setResourceStateType(DataConstraintModel.typeJson); + } } public ResourceHierarchy(ResourceHierarchy parent, int numParameters) { @@ -46,6 +53,47 @@ this.numParameters = numParameters; } + public ResourceHierarchy(ResourceHierarchy parent, Expression parameterExp) { + this.parent = parent; + this.resourceName = null; + this.numParameters = 1; + if (parent != null && parent.getResourceStateType() == null) { + Type paramType = null; + if (parameterExp instanceof Variable) { + paramType = ((Variable) parameterExp).getType(); + } else if (parameterExp instanceof Term) { + paramType = ((Term) parameterExp).getType(); + } + if (paramType != null) { + if (paramType.equals(DataConstraintModel.typeInt)) { + parent.setResourceStateType(DataConstraintModel.typeList); + } else if (paramType.equals(DataConstraintModel.typeString)) { + parent.setResourceStateType(DataConstraintModel.typeMap); + } + } + } + } + + public ResourceHierarchy(ResourceHierarchy parent, Expression parameterExp, Type resourceStateType) { + this.parent = parent; + this.resourceName = null; + this.numParameters = 1; + this.resourceStateType = resourceStateType; + if (parent != null && parent.getResourceStateType() == null) { + Type paramType = null; + if (parameterExp instanceof Variable) { + paramType = ((Variable) parameterExp).getType(); + } else if (parameterExp instanceof Term) { + paramType = ((Term) parameterExp).getType(); + } + if (paramType.equals(DataConstraintModel.typeInt)) { + parent.setResourceStateType(DataConstraintModel.typeList); + } else if (paramType.equals(DataConstraintModel.typeString)) { + parent.setResourceStateType(DataConstraintModel.typeMap); + } + } + } + public ResourceHierarchy(ResourceHierarchy parent, int numParameters, Type resourceStateType) { this.parent = parent; this.resourceName = null; diff --git a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/ResourcePath.java b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/ResourcePath.java index cc427ef..09ab11f 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/ResourcePath.java +++ b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/ResourcePath.java @@ -32,19 +32,10 @@ public ResourcePath(ResourcePath parent, Expression exp) { super(parent.toString() + ".{" + exp + "}"); this.parent = parent; - this.resourceHierarchy = new ResourceHierarchy(parent.getResourceHierarchy(), 1); + this.resourceHierarchy = new ResourceHierarchy(parent.getResourceHierarchy(), exp); this.pathParams = new ArrayList<>(parent.getPathParams()); this.pathParams.add(exp); } - - public ResourcePath(ResourcePath parent, List pathParams) { - super(parent.toString() + ".{" + pathParams.toString() + "}"); - this.parent = parent; - this.resourceHierarchy = new ResourceHierarchy(parent.getResourceHierarchy(), pathParams.size()); - this.pathParams = new ArrayList<>(parent.getPathParams()); - this.pathParams.addAll(pathParams); - } - public ResourceHierarchy getResourceHierarchy() { return resourceHierarchy; @@ -82,6 +73,18 @@ pathParams.add(pathParam); } + public boolean endsWithParam() { + if (resourceHierarchy.getNumParameters() > 0) return true; + return false; + } + + public Expression getLastParam() { + if (endsWithParam()) { + return pathParams.get(pathParams.size() - 1); + } + return null; + } + public ResourcePath getParent() { return parent; } diff --git a/AlgebraicDataflowArchitectureModel/src/parser/Parser.java b/AlgebraicDataflowArchitectureModel/src/parser/Parser.java index bf8d96d..4409fb1 100644 --- a/AlgebraicDataflowArchitectureModel/src/parser/Parser.java +++ b/AlgebraicDataflowArchitectureModel/src/parser/Parser.java @@ -1,6 +1,5 @@ package parser; -import java.awt.image.DataBufferDouble; import java.io.BufferedReader; import java.io.IOException; import java.util.ArrayList; @@ -14,6 +13,8 @@ import models.algebra.Type; import models.algebra.Variable; import models.dataConstraintModel.ChannelMember; +import models.dataConstraintModel.DataConstraintModel; +import models.dataConstraintModel.JsonAccessor; import models.dataConstraintModel.ResourceHierarchy; import models.dataConstraintModel.ResourcePath; import models.dataConstraintModel.StateTransition; @@ -30,6 +31,7 @@ import parser.exceptions.ExpectedRightBracket; import parser.exceptions.ExpectedRightCurlyBracket; import parser.exceptions.ExpectedStateTransition; +import parser.exceptions.WrongJsonExpression; import parser.exceptions.WrongLHSExpression; import parser.exceptions.WrongPathExpression; import parser.exceptions.WrongRHSExpression; @@ -87,14 +89,14 @@ public DataTransferModel doParse() throws ExpectedRightBracket, ExpectedChannel, ExpectedChannelName, ExpectedLeftCurlyBracket, ExpectedRightCurlyBracket, ExpectedInOrOutOrRefOrSubKeyword, ExpectedStateTransition, ExpectedEquals, - ExpectedRHSExpression, WrongLHSExpression, WrongRHSExpression, ExpectedAssignment, WrongPathExpression { + ExpectedRHSExpression, WrongLHSExpression, WrongRHSExpression, ExpectedAssignment, WrongPathExpression, WrongJsonExpression { return parseDataFlowModel(); } public DataTransferModel parseDataFlowModel() throws ExpectedRightBracket, ExpectedChannel, ExpectedChannelName, ExpectedLeftCurlyBracket, ExpectedRightCurlyBracket, ExpectedInOrOutOrRefOrSubKeyword, ExpectedStateTransition, ExpectedEquals, - ExpectedRHSExpression, WrongLHSExpression, WrongRHSExpression, ExpectedAssignment, WrongPathExpression { + ExpectedRHSExpression, WrongLHSExpression, WrongRHSExpression, ExpectedAssignment, WrongPathExpression, WrongJsonExpression { DataTransferModel model = new DataTransferModel(); DataTransferChannel channel; while ((channel = parseChannel(model)) != null) { @@ -111,7 +113,7 @@ throws ExpectedLeftCurlyBracket, ExpectedRightBracket, ExpectedRightCurlyBracket, ExpectedAssignment, ExpectedRHSExpression, WrongLHSExpression, WrongRHSExpression, ExpectedChannel, ExpectedChannelName, ExpectedInOrOutOrRefOrSubKeyword, - ExpectedStateTransition, ExpectedEquals, WrongPathExpression { + ExpectedStateTransition, ExpectedEquals, WrongPathExpression, WrongJsonExpression { if (!stream.hasNext()) return null; if (stream.checkNext().equals(RIGHT_CURLY_BRACKET)) return null; @@ -178,7 +180,7 @@ public void parseInit(DataTransferModel model) throws ExpectedLeftCurlyBracket, ExpectedAssignment, ExpectedRHSExpression, WrongRHSExpression, - ExpectedRightBracket, ExpectedRightCurlyBracket, WrongPathExpression { + ExpectedRightBracket, ExpectedRightCurlyBracket, WrongPathExpression, WrongJsonExpression { String leftBracket = stream.next(); if (!leftBracket.equals(LEFT_CURLY_BRACKET)) throw new ExpectedLeftCurlyBracket(stream.getLine()); while (stream.hasNext() && !stream.checkNext().equals(RIGHT_CURLY_BRACKET)) { @@ -205,7 +207,7 @@ public ChannelMember parseChannelMember(DataTransferModel model, final String inOrOutOrRef) throws ExpectedRightBracket, ExpectedRightCurlyBracket, ExpectedStateTransition, ExpectedEquals, - ExpectedRHSExpression, WrongLHSExpression, WrongRHSExpression, WrongPathExpression { + ExpectedRHSExpression, WrongLHSExpression, WrongRHSExpression, WrongPathExpression, WrongJsonExpression { if (!stream.hasNext()) throw new ExpectedStateTransition(stream.getLine()); StateTransitionTerm leftTerm = parseStateTransitionTerm(stream, model); if (leftTerm == null || !(leftTerm instanceof Term)) throw new WrongLHSExpression(stream.getLine()); @@ -252,7 +254,7 @@ return channelMember; } - public Expression parseTerm(TokenStream stream, DataTransferModel model) throws ExpectedRightBracket { + public Expression parseTerm(TokenStream stream, DataTransferModel model) throws ExpectedRightBracket, WrongJsonExpression { ArrayList expressions = new ArrayList<>(); ArrayList operators = new ArrayList<>(); String operator = null; @@ -294,18 +296,19 @@ symbol.setArity(arity); exp = term; } else { - // constant or variable - try { - if (stream.checkNext() != null && stream.checkNext().equals(DOT)) { - // Because tokens are separated by a DOT. - stream.next(); - symbolName += DOT + stream.next(); // decimal fraction - } - Symbol symbol = model.getSymbol(symbolName); - if (symbol != null && symbol.getArity() == 0) { - // a constant - exp = new Constant(symbol); - } else { + // constant or variable or json access + Symbol symbol = model.getSymbol(symbolName); + if (symbol != null && symbol.getArity() == 0) { + // a constant + exp = new Constant(symbol); + } else { + if (Character.isDigit(symbolName.charAt(0))) { + // maybe a numerical value + if (stream.checkNext() != null && stream.checkNext().equals(DOT)) { + // Because tokens are separated by a DOT. + stream.next(); + symbolName += DOT + stream.next(); // decimal fraction + } Double d = Double.parseDouble(symbolName); // a numerical value if (symbolName.contains(DOT)) { @@ -313,10 +316,10 @@ } else { exp = new Constant(symbolName, DataTransferModel.typeInt); } + } else { + // a variable + exp = parseVariable(stream, model, symbolName); } - } catch (NumberFormatException e) { - // a variable - exp = parseVariable(stream, model, symbolName); } } if (minus != null) { @@ -332,16 +335,52 @@ break; } else if (operator.equals(ADD)) { operators.add(DataTransferModel.add); + stream.next(); } else if (operator.equals(MUL)) { operators.add(DataTransferModel.mul); + stream.next(); } else if (operator.equals(SUB)) { operators.add(DataTransferModel.sub); // not minus + stream.next(); } else if (operator.equals(DIV)) { operators.add(DataTransferModel.div); + stream.next(); + } else if (operator.equals(DOT)) { + // json accessor + Expression exp = expressions.remove(0); + stream.next(); // DOT + if (stream.checkNext() == null) throw new WrongJsonExpression(stream.getLine()); + String literalOrLeftCurlyBracket = stream.next(); + Expression paramTerm = null; + if (literalOrLeftCurlyBracket.equals(LEFT_CURLY_BRACKET)) { + // parameter + paramTerm = parseTerm(stream, model); + String rightCurlyBracket = stream.next(); + if (rightCurlyBracket == null || !rightCurlyBracket.equals(RIGHT_CURLY_BRACKET)) throw new WrongJsonExpression(stream.getLine()); + } else { + // literal + paramTerm = new Constant(literalOrLeftCurlyBracket, DataTransferModel.typeString); + } + Type paramType = null; + if (paramTerm instanceof Variable) { + paramType = ((Variable) paramTerm).getType(); + } else if (paramTerm instanceof Term) { + paramType = ((Term) paramTerm).getType(); + } + Term term = null; + if (paramType != null && DataConstraintModel.typeInt.isAncestorOf(paramType)) { + term = new JsonAccessor(DataConstraintModel.dotParam); + } else { + term = new JsonAccessor(DataConstraintModel.dot); + } + term.addChild(exp); + term.addChild(paramTerm); + expressions.add(term); + operator = stream.checkNext(); + if (operator == null || !operator.equals(DOT)) break; } else { break; } - stream.next(); // an arithmetic operator } if (expressions.size() == 1) { // no arithmetic operators @@ -397,7 +436,7 @@ return var; } - public StateTransitionTerm parseStateTransitionTerm(TokenStream stream, DataTransferModel model) throws ExpectedRightBracket, ExpectedRightCurlyBracket, WrongPathExpression { + public StateTransitionTerm parseStateTransitionTerm(TokenStream stream, DataTransferModel model) throws ExpectedRightBracket, ExpectedRightCurlyBracket, WrongPathExpression, WrongJsonExpression { ResourcePath resourcePath = parseResourcePath(stream, model); StateTransitionTerm term = new StateTransitionTerm(resourcePath); int arity = 0; @@ -433,18 +472,16 @@ return hierarchy; } - public ResourcePath parseResourcePath(TokenStream stream, DataTransferModel model) throws ExpectedRightBracket, ExpectedRightCurlyBracket, WrongPathExpression { + public ResourcePath parseResourcePath(TokenStream stream, DataTransferModel model) throws ExpectedRightBracket, ExpectedRightCurlyBracket, WrongPathExpression, WrongJsonExpression { ResourcePath path = null; - List pathParams = new ArrayList<>(); do { String literalOrLeftCurlyBracket = stream.next(); if (literalOrLeftCurlyBracket.equals(LEFT_CURLY_BRACKET)) { // Path parameter Expression paramTerm = parseTerm(stream, model); - pathParams.add(paramTerm); String rightCurlyBracket = stream.next(); if (rightCurlyBracket == null || !rightCurlyBracket.equals(RIGHT_CURLY_BRACKET)) throw new ExpectedRightCurlyBracket(stream.getLine()); - path = new ResourcePath(path, pathParams); + path = new ResourcePath(path, paramTerm); } else { // Path literal if (path == null) { diff --git a/AlgebraicDataflowArchitectureModel/src/parser/ParserDTRAM.java b/AlgebraicDataflowArchitectureModel/src/parser/ParserDTRAM.java index 2c7848c..6a991d5 100644 --- a/AlgebraicDataflowArchitectureModel/src/parser/ParserDTRAM.java +++ b/AlgebraicDataflowArchitectureModel/src/parser/ParserDTRAM.java @@ -27,6 +27,7 @@ import parser.exceptions.ExpectedRightBracket; import parser.exceptions.ExpectedRightCurlyBracket; import parser.exceptions.ExpectedStateTransition; +import parser.exceptions.WrongJsonExpression; import parser.exceptions.WrongLHSExpression; import parser.exceptions.WrongPathExpression; import parser.exceptions.WrongRHSExpression; @@ -63,9 +64,10 @@ /**-------------------------------------------------------------------------------- * * @param reader + * @throws WrongJsonExpression */ public DataTransferModel doParseModel() - throws ExpectedRightBracket, ExpectedChannel, ExpectedChannelName, ExpectedLeftCurlyBracket, ExpectedInOrOutOrRefOrSubKeyword, ExpectedStateTransition, ExpectedEquals, ExpectedRHSExpression, WrongLHSExpression, WrongRHSExpression, ExpectedAssignment, ExpectedModel, ExpectedGeometry, ExpectedRightCurlyBracket, WrongPathExpression { + throws ExpectedRightBracket, ExpectedChannel, ExpectedChannelName, ExpectedLeftCurlyBracket, ExpectedInOrOutOrRefOrSubKeyword, ExpectedStateTransition, ExpectedEquals, ExpectedRHSExpression, WrongLHSExpression, WrongRHSExpression, ExpectedAssignment, ExpectedModel, ExpectedGeometry, ExpectedRightCurlyBracket, WrongPathExpression, WrongJsonExpression { DataTransferModel model = getParsedModel(); return model; } @@ -85,9 +87,10 @@ /**-------------------------------------------------------------------------------- * * @param stream + * @throws WrongJsonExpression */ private DataTransferModel getParsedModel() - throws ExpectedRightBracket, ExpectedChannel, ExpectedChannelName, ExpectedLeftCurlyBracket, ExpectedInOrOutOrRefOrSubKeyword, ExpectedStateTransition, ExpectedEquals, ExpectedRHSExpression, WrongLHSExpression, WrongRHSExpression, ExpectedAssignment, ExpectedModel, ExpectedGeometry, ExpectedRightCurlyBracket, WrongPathExpression { + throws ExpectedRightBracket, ExpectedChannel, ExpectedChannelName, ExpectedLeftCurlyBracket, ExpectedInOrOutOrRefOrSubKeyword, ExpectedStateTransition, ExpectedEquals, ExpectedRHSExpression, WrongLHSExpression, WrongRHSExpression, ExpectedAssignment, ExpectedModel, ExpectedGeometry, ExpectedRightCurlyBracket, WrongPathExpression, WrongJsonExpression { if (!stream.hasNext()) throw new NullPointerException(); diff --git a/AlgebraicDataflowArchitectureModel/src/parser/exceptions/WrongJsonExpression.java b/AlgebraicDataflowArchitectureModel/src/parser/exceptions/WrongJsonExpression.java new file mode 100644 index 0000000..6a84d6f --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/parser/exceptions/WrongJsonExpression.java @@ -0,0 +1,9 @@ +package parser.exceptions; + +public class WrongJsonExpression extends ParseException { + + public WrongJsonExpression(int line) { + super(line); + } + +} diff --git a/AlgebraicDataflowArchitectureModel/src/tests/CodeGeneratorTest.java b/AlgebraicDataflowArchitectureModel/src/tests/CodeGeneratorTest.java index 8cca610..65e966a 100644 --- a/AlgebraicDataflowArchitectureModel/src/tests/CodeGeneratorTest.java +++ b/AlgebraicDataflowArchitectureModel/src/tests/CodeGeneratorTest.java @@ -24,6 +24,7 @@ import parser.exceptions.ExpectedRightBracket; import parser.exceptions.ExpectedRightCurlyBracket; import parser.exceptions.ExpectedStateTransition; +import parser.exceptions.WrongJsonExpression; import parser.exceptions.WrongLHSExpression; import parser.exceptions.WrongPathExpression; import parser.exceptions.WrongRHSExpression; @@ -43,7 +44,7 @@ System.out.println(codetree); } catch (ExpectedChannel | ExpectedChannelName | ExpectedLeftCurlyBracket | ExpectedInOrOutOrRefOrSubKeyword | ExpectedStateTransition | ExpectedEquals | ExpectedRHSExpression | WrongLHSExpression - | WrongRHSExpression | ExpectedRightBracket | ExpectedAssignment | ExpectedRightCurlyBracket | WrongPathExpression e) { + | WrongRHSExpression | ExpectedRightBracket | ExpectedAssignment | ExpectedRightCurlyBracket | WrongPathExpression | WrongJsonExpression e) { e.printStackTrace(); } } catch (FileNotFoundException e) { diff --git a/AlgebraicDataflowArchitectureModel/src/tests/DataStorageDecisionTest.java b/AlgebraicDataflowArchitectureModel/src/tests/DataStorageDecisionTest.java index 7326b58..3f1d16f 100644 --- a/AlgebraicDataflowArchitectureModel/src/tests/DataStorageDecisionTest.java +++ b/AlgebraicDataflowArchitectureModel/src/tests/DataStorageDecisionTest.java @@ -20,6 +20,7 @@ import parser.exceptions.ExpectedRightBracket; import parser.exceptions.ExpectedRightCurlyBracket; import parser.exceptions.ExpectedStateTransition; +import parser.exceptions.WrongJsonExpression; import parser.exceptions.WrongLHSExpression; import parser.exceptions.WrongPathExpression; import parser.exceptions.WrongRHSExpression; @@ -41,7 +42,7 @@ } } catch (ExpectedChannel | ExpectedChannelName | ExpectedLeftCurlyBracket | ExpectedInOrOutOrRefOrSubKeyword | ExpectedStateTransition | ExpectedEquals | ExpectedRHSExpression | WrongLHSExpression - | WrongRHSExpression | ExpectedRightBracket | ExpectedAssignment | ExpectedRightCurlyBracket | WrongPathExpression e) { + | WrongRHSExpression | ExpectedRightBracket | ExpectedAssignment | ExpectedRightCurlyBracket | WrongPathExpression | WrongJsonExpression e) { e.printStackTrace(); } } catch (FileNotFoundException e) { diff --git a/AlgebraicDataflowArchitectureModel/src/tests/DataStorageNecessityTest.java b/AlgebraicDataflowArchitectureModel/src/tests/DataStorageNecessityTest.java index 5a4eb65..2fc3a42 100644 --- a/AlgebraicDataflowArchitectureModel/src/tests/DataStorageNecessityTest.java +++ b/AlgebraicDataflowArchitectureModel/src/tests/DataStorageNecessityTest.java @@ -19,6 +19,7 @@ import parser.exceptions.ExpectedRightBracket; import parser.exceptions.ExpectedRightCurlyBracket; import parser.exceptions.ExpectedStateTransition; +import parser.exceptions.WrongJsonExpression; import parser.exceptions.WrongLHSExpression; import parser.exceptions.WrongPathExpression; import parser.exceptions.WrongRHSExpression; @@ -41,7 +42,7 @@ } } catch (ExpectedChannel | ExpectedChannelName | ExpectedLeftCurlyBracket | ExpectedInOrOutOrRefOrSubKeyword | ExpectedStateTransition | ExpectedEquals | ExpectedRHSExpression | WrongLHSExpression - | WrongRHSExpression | ExpectedRightBracket | ExpectedAssignment | ExpectedRightCurlyBracket | WrongPathExpression e) { + | WrongRHSExpression | ExpectedRightBracket | ExpectedAssignment | ExpectedRightCurlyBracket | WrongPathExpression | WrongJsonExpression e) { e.printStackTrace(); } } catch (FileNotFoundException e) { diff --git a/AlgebraicDataflowArchitectureModel/src/tests/EdgeTransitionSelectableTest.java b/AlgebraicDataflowArchitectureModel/src/tests/EdgeTransitionSelectableTest.java index afd9e6d..093cbc0 100644 --- a/AlgebraicDataflowArchitectureModel/src/tests/EdgeTransitionSelectableTest.java +++ b/AlgebraicDataflowArchitectureModel/src/tests/EdgeTransitionSelectableTest.java @@ -19,6 +19,7 @@ import parser.exceptions.ExpectedRightBracket; import parser.exceptions.ExpectedRightCurlyBracket; import parser.exceptions.ExpectedStateTransition; +import parser.exceptions.WrongJsonExpression; import parser.exceptions.WrongLHSExpression; import parser.exceptions.WrongPathExpression; import parser.exceptions.WrongRHSExpression; @@ -40,7 +41,7 @@ } } catch (ExpectedChannel | ExpectedChannelName | ExpectedLeftCurlyBracket | ExpectedInOrOutOrRefOrSubKeyword | ExpectedStateTransition | ExpectedEquals | ExpectedRHSExpression | WrongLHSExpression - | WrongRHSExpression | ExpectedRightBracket | ExpectedAssignment | ExpectedRightCurlyBracket | WrongPathExpression e) { + | WrongRHSExpression | ExpectedRightBracket | ExpectedAssignment | ExpectedRightCurlyBracket | WrongPathExpression | WrongJsonExpression e) { e.printStackTrace(); } } catch (FileNotFoundException e) { diff --git a/AlgebraicDataflowArchitectureModel/src/tests/InverseTest.java b/AlgebraicDataflowArchitectureModel/src/tests/InverseTest.java index 85644fc..c40de8a 100644 --- a/AlgebraicDataflowArchitectureModel/src/tests/InverseTest.java +++ b/AlgebraicDataflowArchitectureModel/src/tests/InverseTest.java @@ -16,10 +16,13 @@ import models.algebra.Position; import models.algebra.Term; import models.algebra.Variable; +import models.dataConstraintModel.DataConstraintModel; +import models.dataConstraintModel.JsonType; import models.dataFlowModel.DataTransferModel; import parser.Parser; import parser.Parser.TokenStream; import parser.exceptions.ExpectedRightBracket; +import parser.exceptions.WrongJsonExpression; public class InverseTest { @Test @@ -75,7 +78,7 @@ HashMap rhsVars3 = rhsExp3.getVariables(); for (Position vPos: rhsVars3.keySet()) { Variable v = rhsVars3.get(vPos); - Expression inv = rhsExp3.getInverseMap(z, vPos); // inverse map to get v back from the output value y + Expression inv = rhsExp3.getInverseMap(z, vPos); // inverse map to get v back from the output value z if (inv instanceof Term) { inv = ((Term) inv).reduce(); } @@ -83,7 +86,31 @@ assertFalse(inv.contains(v)); System.out.println(rhsVars3.get(vPos) + " = " + inv); } - } catch (ExpectedRightBracket e) { + + // Solve {z = x.id} for x + TokenStream stream4 = new Parser.TokenStream(); + Parser parser4 = new Parser(stream4); + stream4.addLine("x.id"); + Expression rhsExp4 = parser4.parseTerm(stream4, model); + System.out.println("=== solve{" + z + " = " + rhsExp4 + "} for x ==="); + HashMap rhsVars4 = rhsExp4.getVariables(); + for (Position vPos: rhsVars4.keySet()) { + Variable v = rhsVars4.get(vPos); + if (x.getName().equals("x")) { + JsonType jsonType = new JsonType("Json", "HashMap<>", DataConstraintModel.typeJson); + jsonType.addMemberType("id", DataConstraintModel.typeInt); + jsonType.addMemberType("name", DataConstraintModel.typeString); + v.setType(jsonType); + } + Expression inv = rhsExp4.getInverseMap(z, vPos); // inverse map to get v back from the output value z + if (inv instanceof Term) { + inv = ((Term) inv).reduce(); + } + System.out.println(rhsVars4.get(vPos) + " = " + inv); + assertTrue(inv.contains(z)); + assertFalse(inv.contains(v)); + } + } catch (ExpectedRightBracket | WrongJsonExpression e) { e.printStackTrace(); } } diff --git a/AlgebraicDataflowArchitectureModel/src/tests/UpdateConflictCheckTest.java b/AlgebraicDataflowArchitectureModel/src/tests/UpdateConflictCheckTest.java index 112b4d6..3b8065d 100644 --- a/AlgebraicDataflowArchitectureModel/src/tests/UpdateConflictCheckTest.java +++ b/AlgebraicDataflowArchitectureModel/src/tests/UpdateConflictCheckTest.java @@ -18,6 +18,7 @@ import parser.exceptions.ExpectedRightBracket; import parser.exceptions.ExpectedRightCurlyBracket; import parser.exceptions.ExpectedStateTransition; +import parser.exceptions.WrongJsonExpression; import parser.exceptions.WrongLHSExpression; import parser.exceptions.WrongPathExpression; import parser.exceptions.WrongRHSExpression; @@ -34,7 +35,7 @@ } catch (ExpectedRightBracket | ExpectedChannel | ExpectedChannelName | ExpectedLeftCurlyBracket | ExpectedRightCurlyBracket | ExpectedInOrOutOrRefOrSubKeyword | ExpectedStateTransition | ExpectedEquals | ExpectedRHSExpression | WrongLHSExpression | WrongRHSExpression | ExpectedAssignment - | WrongPathExpression e) { + | WrongPathExpression | WrongJsonExpression e) { e.printStackTrace(); } } catch (FileNotFoundException e) { diff --git a/AlgebraicDataflowArchitectureModel/src/tests/parser/ParseTest.java b/AlgebraicDataflowArchitectureModel/src/tests/parser/ParseTest.java index 0076e51..67cf1d2 100644 --- a/AlgebraicDataflowArchitectureModel/src/tests/parser/ParseTest.java +++ b/AlgebraicDataflowArchitectureModel/src/tests/parser/ParseTest.java @@ -24,6 +24,7 @@ import parser.exceptions.ExpectedRightBracket; import parser.exceptions.ExpectedRightCurlyBracket; import parser.exceptions.ExpectedStateTransition; +import parser.exceptions.WrongJsonExpression; import parser.exceptions.WrongLHSExpression; import parser.exceptions.WrongPathExpression; import parser.exceptions.WrongRHSExpression; @@ -56,7 +57,7 @@ | ExpectedStateTransition | ExpectedEquals | ExpectedRHSExpression | WrongLHSExpression | WrongRHSExpression | ExpectedRightBracket | ParameterizedIdentifierIsFutureWork | ResolvingMultipleDefinitionIsFutureWork | InvalidMessage - | UnificationFailed | ValueUndefined | ExpectedAssignment | ExpectedRightCurlyBracket | WrongPathExpression e) { + | UnificationFailed | ValueUndefined | ExpectedAssignment | ExpectedRightCurlyBracket | WrongPathExpression | WrongJsonExpression e) { e.printStackTrace(); } } catch (FileNotFoundException e) {