diff --git a/AlgebraicDataflowArchitectureModel/models/Audio.dtram b/AlgebraicDataflowArchitectureModel/models/Audio.dtram new file mode 100644 index 0000000..66862ef --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/models/Audio.dtram @@ -0,0 +1,33 @@ +model { +channel CIO3 { + out BGMVolume(b: Double, setBGM(b2)) == b2 +} +channel CIO2 { + out soundVolume(s: Double, setSound(s2)) == s2 +} +channel CIO1 { + out audioVolume(a: Double, setAudio(a2)) == a2 +} +channel C1 { + in audioVolume(a, calc(a2, s2)) == a2 + in soundVolume(s, calc(a2, s2)) == s2 + out outputSoundVolume(os, calc(a2, s2)) == a2 * s2 +} +channel C2 { + in audioVolume(a, calc(a2, b2)) == a2 + in BGMVolume(b, calc(a2, b2)) == b2 + out outputBGMVolume(ob, calc(a2, b2)) == a2 * b2 +} +} +geometry { + node r soundVolume:220,140,80,30 + node r audioVolume:220,280,80,30 + node r outputSoundVolume:650,190,80,30 + node r BGMVolume:220,420,80,30 + node r outputBGMVolume:650,340,80,30 + node ioc CIO3:100,420,30,30 + node ioc CIO2:100,140,30,30 + node ioc CIO1:100,280,30,30 + node c C1:530,190,30,30 + node c C2:530,340,30,30 +} diff --git a/AlgebraicDataflowArchitectureModel/models/Clock.dtram b/AlgebraicDataflowArchitectureModel/models/Clock.dtram index f619eaf..ae2169e 100644 --- a/AlgebraicDataflowArchitectureModel/models/Clock.dtram +++ b/AlgebraicDataflowArchitectureModel/models/Clock.dtram @@ -1,27 +1,27 @@ model { -channel CIO1 { - out min(m: Int, tick) == mod(m + 1, 60) -} -channel HourUpdate { - in hour(h: Int, update(h2)) == h2 - out hour_hand(h_ang: Float, update(h2)) == h2 / 6 * PI -} -channel MinUpdate { - in min(m, update(m2)) == m2 - out min_hand(m_ang: Float, update(m2)) == m2 / 30 * PI -} -channel Clock { - in min(m, update(m2)) == m2 - out hour(h, update(m2)) == if(eq(m2, 0), mod(h + 1, 24), h) -} + channel CIO1 { + out min(m: Double, tick) == mod(m + 1, 60) + } + channel Clock { + in min(m, update(m2)) == m2 + out hour(h: Double, update(m2)) == if(eq(m2, 0), mod(h + 1, 24), h) + } + channel MinUpdate { + in min(m, update(m2)) == m2 + out min_ang(m_ang: Double, update(m2)) == m2 / 30 * PI + } + channel HourUpdate { + in hour(h, update(h2)) == h2 + out hour_ang(h_ang: Double, update(h2)) == h2 / 6 * PI + } } geometry { node c HourUpdate:520,340,30,30 node c MinUpdate:520,100,30,30 node c Clock:280,220,30,30 - node r min_hand:670,100,80,30 + node r min_ang:670,100,80,30 node r min:250,100,80,30 node r hour:270,340,80,30 - node r hour_hand:680,340,80,30 + node r hour_ang:680,340,80,30 node ioc CIO1:100,100,30,30 } diff --git a/AlgebraicDataflowArchitectureModel/src/algorithms/TypeInference.java b/AlgebraicDataflowArchitectureModel/src/algorithms/TypeInference.java index d29070d..a18b3c1 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,6 +23,7 @@ import models.dataConstraintModel.Channel; import models.dataConstraintModel.ChannelMember; import models.dataConstraintModel.DataConstraintModel; +import models.dataConstraintModel.JsonType; import models.dataConstraintModel.ResourcePath; import models.dataConstraintModel.StateTransition; import models.dataFlowModel.DataTransferModel; @@ -42,6 +44,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); @@ -83,6 +87,14 @@ 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 variables = new HashMap<>(); @@ -91,6 +103,9 @@ 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> expToVariable = new HashMap<>(); Map> expToMessage = new HashMap<>(); @@ -98,7 +113,9 @@ 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<>(); Map> updateFromVariable = new HashMap<>(); Map> updateFromMessage = new HashMap<>(); @@ -106,6 +123,7 @@ 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); @@ -128,24 +146,24 @@ for (Channel c : channels) { for (ChannelMember cm : c.getChannelMembers()) { StateTransition st = cm.getStateTransition(); - ResourcePath id = cm.getResource(); + ResourcePath res = cm.getResource(); // 1.1 Group expressions by resources. - List sameResource = resources.get(id); + List sameResource = resources.get(res); if (sameResource == null) { sameResource = new ArrayList<>(); - resources.put(id, sameResource); + resources.put(res, sameResource); } 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); - Type resType = id.getResourceStateType(); + Type resType = res.getResourceStateType(); Expression exp = st.getCurStateExpression(); Type expType = getExpTypeIfUpdatable(resType, exp); if (expType != null) { - id.setResourceStateType(expType); + res.setResourceStateType(expType); for (Expression resExp : sameResource) { if (resExp != exp) { if (resExp instanceof Variable && compareTypes(((Variable) resExp).getType(), expType)) { @@ -168,12 +186,12 @@ updatedExps.put(System.identityHashCode(exp), exp); } } - resType = id.getResourceStateType(); + resType = res.getResourceStateType(); exp = st.getNextStateExpression(); if (exp != null) { expType = getExpTypeIfUpdatable(resType, exp); if (expType != null) { - id.setResourceStateType(expType); + res.setResourceStateType(expType); for (Expression resExp : sameResource) { if (resExp != exp) { if (resExp instanceof Variable && compareTypes(((Variable) resExp).getType(), expType)) { @@ -343,7 +361,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. @@ -354,10 +372,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)); @@ -410,9 +428,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()); @@ -446,11 +464,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) { @@ -482,26 +500,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); @@ -510,22 +529,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); @@ -540,11 +559,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(); @@ -553,16 +572,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; @@ -578,10 +598,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) { @@ -591,27 +611,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; @@ -627,11 +648,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(); @@ -640,13 +661,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) { @@ -665,10 +686,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) { @@ -678,13 +699,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) { @@ -716,21 +737,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; @@ -757,33 +779,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); @@ -929,7 +1104,8 @@ // 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) { if (updateFromResource.size() > 0) { Set resourceKeys = updateFromResource.keySet(); Integer resourceKey = resourceKeys.iterator().next(); @@ -943,6 +1119,7 @@ updateTupleTypes(resExp, tuple, expToTuple, updateFromTuple); updatePairTypes(resExp, pair, expToPair, updateFromPair); updateMapTypes(resExp, map, expToMap, updateFromMap); + updateJsonTypes(resExp, json, expToJson, updateFromJson); } } if (updateFromVariable.size() > 0) { @@ -959,6 +1136,7 @@ updateTupleTypes(var, tuple, expToTuple, updateFromTuple); updatePairTypes(var, pair, expToPair, updateFromPair); updateMapTypes(var, map, expToMap, updateFromMap); + updateJsonTypes(var, json, expToJson, updateFromJson); } } if (updateFromMessage.size() > 0) { @@ -974,6 +1152,7 @@ updateTupleTypes(mesExp, tuple, expToTuple, updateFromTuple); updatePairTypes(mesExp, pair, expToPair, updateFromPair); updateMapTypes(mesExp, map, expToMap, updateFromMap); + updateJsonTypes(mesExp, json, expToJson, updateFromJson); } } if (updateFromConsOrSet.size() > 0) { @@ -990,6 +1169,7 @@ updateTupleTypes(consExp, tuple, expToTuple, updateFromTuple); updatePairTypes(consExp, pair, expToPair, updateFromPair); updateMapTypes(consExp, map, expToMap, updateFromMap); + updateJsonTypes(consExp, json, expToJson, updateFromJson); } } if (updateFromTuple.size() > 0) { @@ -1006,6 +1186,7 @@ updateTupleTypes(tupleExp, tuple, expToTuple, updateFromTuple); updatePairTypes(tupleExp, pair, expToPair, updateFromPair); updateMapTypes(tupleExp, map, expToMap, updateFromMap); + updateJsonTypes(tupleExp, json, expToJson, updateFromJson); } } if (updateFromPair.size() > 0) { @@ -1022,6 +1203,7 @@ updateTupleTypes(pairExp, tuple, expToTuple, updateFromTuple); updatePairTypes(pairExp, pair, expToPair, updateFromPair); updateMapTypes(pairExp, map, expToMap, updateFromMap); + updateJsonTypes(pairExp, json, expToJson, updateFromJson); } } if (updateFromMap.size() > 0) { @@ -1038,6 +1220,24 @@ 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); + 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); } } } @@ -1060,12 +1260,12 @@ Map> expToResource, Map> updateFromResource) { List sameResource = expToResource.get(System.identityHashCode(exp)); if (sameResource == null) return; - for (ResourcePath id : resources.keySet()) { - if (resources.get(id) == sameResource) { - Type resType = id.getResourceStateType(); + for (ResourcePath res : resources.keySet()) { + if (resources.get(res) == sameResource) { + Type resType = res.getResourceStateType(); Type newResType = getExpTypeIfUpdatable(resType, exp); if (newResType != null) { - id.setResourceStateType(newResType); + res.setResourceStateType(newResType); Map updateExps = getUpdateSet(updateFromResource, sameResource); for (Expression resExp : sameResource) { if (resExp != exp) { @@ -1167,6 +1367,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); @@ -1191,6 +1392,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); @@ -1216,6 +1418,7 @@ } break; case 2: + // exp is a list itself. listType = consOrSet.get(System.identityHashCode(consOrSetComponentGroup)); expType = getExpTypeIfUpdatable(listType, exp); if (expType != null) { @@ -1245,6 +1448,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) { @@ -1312,6 +1516,7 @@ } } } else { + // exp is a tuple's component. Type tupleType = tuple.get(System.identityHashCode(tupleComponentGroup)); List componentTypes = tupleComponentTypes.get(tupleType); boolean updated = false; @@ -1382,6 +1587,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) { @@ -1405,6 +1611,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); @@ -1435,6 +1642,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) { @@ -1478,6 +1686,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); @@ -1516,6 +1725,116 @@ } } + + 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(); + } + if (memberTypes != null) { + Type memberType = memberTypes.get(keyName); + Type newMemberType = getExpTypeIfUpdatable(memberType, exp); + if (newMemberType != null && keyName != null) { + // Propagate an update of a member's type to its container's (json's) type. + Map newMemberTypes = new HashMap<>(memberTypes); + newMemberTypes.put(keyName, newMemberType); + newJsonType = jsonTypes.get(newMemberTypes); + if (newJsonType == null) { + // Create new json type. + newJsonType = createNewJsonType(newMemberTypes, jsonType); + } + } + } + } + if (newJsonType != null) { + // Update the type of the json term and record the updated expression. + Map updateExps = getUpdateSet(updateFromJson, jsonMemberGroup); + Expression jsonExp = jsonMemberGroup.get(0); + if (jsonExp instanceof Variable) { + ((Variable) jsonExp).setType(newJsonType); + updateExps.put(System.identityHashCode(jsonExp), jsonExp); + } else if (jsonExp instanceof Term) { + ((Term) jsonExp).setType(newJsonType); + updateExps.put(System.identityHashCode(jsonExp), jsonExp); + } + json.put(System.identityHashCode(jsonMemberGroup), newJsonType); + } + } + } + } + private static Type createNewListType(Type compType, Type parentType) { String compTypeName = getInterfaceTypeName(compType); List childrenTypes = getChildrenTypes(parentType, listComponentTypes.keySet()); @@ -1598,9 +1917,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); } @@ -1626,8 +1975,7 @@ return type.getInterfaceTypeName(); } - private static > Map getUpdateSet( - Map> updateSets, U keySet) { + private static > Map getUpdateSet(Map> updateSets, U keySet) { Map updatedExps = updateSets.get(System.identityHashCode(keySet)); if (updatedExps == null) { updatedExps = new HashMap<>(); @@ -1683,6 +2031,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 +2039,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 +2057,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/Editor.java b/AlgebraicDataflowArchitectureModel/src/application/editor/Editor.java index ba453b8..522e0ca 100644 --- a/AlgebraicDataflowArchitectureModel/src/application/editor/Editor.java +++ b/AlgebraicDataflowArchitectureModel/src/application/editor/Editor.java @@ -49,6 +49,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.ParserDTRAM; @@ -253,7 +254,7 @@ return model; } catch (ExpectedChannel | ExpectedChannelName | ExpectedLeftCurlyBracket | ExpectedInOrOutOrRefKeyword | ExpectedStateTransition | ExpectedEquals | ExpectedRHSExpression | WrongLHSExpression - | WrongRHSExpression | ExpectedRightBracket | ExpectedAssignment | ExpectedModel | ExpectedGeometry | ExpectedNode | ExpectedResource | ExpectedFormulaChannel | ExpectedIoChannel e) { + | WrongRHSExpression | ExpectedRightBracket | ExpectedAssignment | ExpectedModel | ExpectedGeometry | ExpectedNode | ExpectedResource | ExpectedFormulaChannel | ExpectedIoChannel | WrongJsonExpression e) { e.printStackTrace(); } } @@ -289,7 +290,7 @@ return model; } catch (ExpectedChannel | ExpectedChannelName | ExpectedLeftCurlyBracket | ExpectedInOrOutOrRefKeyword | ExpectedStateTransition | ExpectedEquals | ExpectedRHSExpression | WrongLHSExpression - | WrongRHSExpression | ExpectedRightBracket | ExpectedAssignment e) { + | WrongRHSExpression | ExpectedRightBracket | ExpectedAssignment | WrongJsonExpression e) { e.printStackTrace(); } } catch (FileNotFoundException e) { diff --git a/AlgebraicDataflowArchitectureModel/src/application/editor/stages/DataFlowCellEditor.java b/AlgebraicDataflowArchitectureModel/src/application/editor/stages/DataFlowCellEditor.java index 117067f..2b9e98a 100644 --- a/AlgebraicDataflowArchitectureModel/src/application/editor/stages/DataFlowCellEditor.java +++ b/AlgebraicDataflowArchitectureModel/src/application/editor/stages/DataFlowCellEditor.java @@ -33,6 +33,7 @@ import parser.Parser; import parser.Parser.TokenStream; import parser.exceptions.ExpectedRightBracket; +import parser.exceptions.WrongJsonExpression; /************************************************************* * @@ -120,7 +121,7 @@ Expression exp = parser.parseTerm(stream, stage.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/stages/DataFlowModelingStage.java b/AlgebraicDataflowArchitectureModel/src/application/editor/stages/DataFlowModelingStage.java index b722f1b..3ba933f 100644 --- a/AlgebraicDataflowArchitectureModel/src/application/editor/stages/DataFlowModelingStage.java +++ b/AlgebraicDataflowArchitectureModel/src/application/editor/stages/DataFlowModelingStage.java @@ -38,6 +38,7 @@ import parser.exceptions.ExpectedRHSExpression; import parser.exceptions.ExpectedRightBracket; import parser.exceptions.ExpectedStateTransition; +import parser.exceptions.WrongJsonExpression; import parser.exceptions.WrongLHSExpression; import parser.exceptions.WrongRHSExpression; @@ -49,6 +50,8 @@ public int PORT_DIAMETER = 8; public int PORT_RADIUS = PORT_DIAMETER / 2; + private boolean bReflectingArchitectureModel = false; + /************************************************************* * [ *constructor] /************************************************************* @@ -173,6 +176,7 @@ * @return constructed mxGraph */ public mxGraph constructGraph(mxGraph graph, DataTransferModel model) { + bReflectingArchitectureModel = true; mxCell root = (mxCell) graph.getDefaultParent(); mxCell nodeLayer = (mxCell) root.getChildAt(NODE_LAYER); mxCell dataFlowLayer = (mxCell) root.getChildAt(DATA_FLOW_LAYER); @@ -254,6 +258,7 @@ graph.getModel().endUpdate(); } + bReflectingArchitectureModel = false; return graph; } @@ -351,6 +356,7 @@ } public boolean connectEdge(mxCell edge, mxCell src, mxCell dst) { + if (bReflectingArchitectureModel) return false; DataTransferModel model = getModel(); Channel srcCh = model.getChannel((String) src.getValue()); if (srcCh == null) { @@ -449,7 +455,7 @@ } } catch (ExpectedRightBracket | ExpectedChannel | ExpectedChannelName | ExpectedLeftCurlyBracket | ExpectedInOrOutOrRefKeyword | ExpectedStateTransition | ExpectedEquals | ExpectedRHSExpression - | WrongLHSExpression | WrongRHSExpression | ExpectedAssignment e) { + | WrongLHSExpression | WrongRHSExpression | ExpectedAssignment | WrongJsonExpression e) { e.printStackTrace(); } } diff --git a/AlgebraicDataflowArchitectureModel/src/generators/CodeGenerator.java b/AlgebraicDataflowArchitectureModel/src/generators/CodeGenerator.java index a61be75..315a158 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/CodeGenerator.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/CodeGenerator.java @@ -2,6 +2,7 @@ import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -74,7 +75,7 @@ ArrayList codes = new ArrayList<>(); // Sort the all components. - ArrayList components = determineComponentOrder(flowGraph); + ArrayList> components = determineComponentOrder(flowGraph); // Add the main component. if (mainTypeName == null) { @@ -91,49 +92,75 @@ return codes; } - public abstract void generateCodeFromFlowGraph(DataTransferModel model, IFlowGraph flowGraph, ArrayList components, + public abstract void generateCodeFromFlowGraph(DataTransferModel model, IFlowGraph flowGraph, ArrayList> components, TypeDeclaration mainComponent, MethodDeclaration mainConstructor, ArrayList codes, ILanguageSpecific langSpec); - private static ArrayList determineComponentOrder(IFlowGraph graph) { - ArrayList objects = new ArrayList<>(); - Set visited = new HashSet<>(); - Set allNodes = graph.getAllNodes(); - for (Node n: allNodes) { - if (!(n instanceof EntryPointObjectNode)) { - topologicalSort(allNodes, n, visited, objects); + private static ArrayList> determineComponentOrder(IFlowGraph graph) { + ArrayList> objects = new ArrayList<>(); + Set> visited = new HashSet<>(); + Map> allNodeSets = graph.getAllNodes(); + for (Set nodeSet: allNodeSets.values()) { + if (!(nodeSet.iterator().next() instanceof EntryPointObjectNode)) { + topologicalSort(allNodeSets, nodeSet, visited, objects); } } return objects; } - private static void topologicalSort(Set allNodes, Node curNode, Set visited, List orderedList) { - if (visited.contains(curNode)) return; - visited.add(curNode); + private static void topologicalSort(Map> allNodeSets, Set curNodeSet, Set> visited, List> orderedList) { + if (visited.contains(curNodeSet)) return; + visited.add(curNodeSet); // a caller is before the callee - for (Edge e: curNode.getInEdges()) { - if (!(e.getSource() instanceof EntryPointObjectNode)) { - if (!(e instanceof DataFlowEdge) || ((PushPullAttribute)((DataFlowEdge) e).getAttribute()).getOptions().get(0) == PushPullValue.PUSH) { - topologicalSort(allNodes, e.getSource(), visited, orderedList); + for (Node curNode: curNodeSet) { + for (Edge e: curNode.getInEdges()) { + if (!(e.getSource() instanceof EntryPointObjectNode)) { + if (!(e instanceof DataFlowEdge) || ((PushPullAttribute)((DataFlowEdge) e).getAttribute()).getOptions().get(0) == PushPullValue.PUSH) { + // for a call edge or PUSH data-flow edge + topologicalSort(allNodeSets, allNodeSets.get(e.getSource()), visited, orderedList); + } } } } - if (curNode instanceof ResourceNode) { - for (Edge e: curNode.getOutEdges()) { - DataFlowEdge de = (DataFlowEdge) e; - if (((PushPullAttribute) de.getAttribute()).getOptions().get(0) != PushPullValue.PUSH) { - topologicalSort(allNodes, e.getDestination(), visited, orderedList); +// if (curNode instanceof StatefulObjectNode) { +// ResourceNode resNode = ((StatefulObjectNode) curNode).getResource(); +// for (Node n: allNodes) { +// if (n != curNode && n instanceof StatefulObjectNode && !visited.contains(n)) { +// if (resNode.equals(((StatefulObjectNode) n).getResource())) { +// // n and curNode are identical (one in PUSH call graph and another in PULL call graph). +// visited.add(n); +// for (Edge e: n.getInEdges()) { +// if (!(e.getSource() instanceof EntryPointObjectNode)) { +// if (!(e instanceof DataFlowEdge)) { +// // for a call edge +// topologicalSort(allNodes, e.getSource(), visited, orderedList); +// } +// } +// } +// } +// } +// } +// } + if (curNodeSet.iterator().next() instanceof ResourceNode) { + for (Node curNode: curNodeSet) { + for (Edge e: curNode.getOutEdges()) { + DataFlowEdge de = (DataFlowEdge) e; + if (((PushPullAttribute) de.getAttribute()).getOptions().get(0) != PushPullValue.PUSH) { + // for a PULL data-flow edge + topologicalSort(allNodeSets, allNodeSets.get(e.getDestination()), visited, orderedList); + } } } } // For reference resources. ResourceNode cn = null; + Node curNode = curNodeSet.iterator().next(); if (curNode instanceof ResourceNode) { cn = (ResourceNode) curNode; } else if (curNode instanceof StatefulObjectNode) { cn = ((StatefulObjectNode) curNode).getResource(); } if (cn != null) { - for (Node n: allNodes) { + for (Node n: allNodeSets.keySet()) { ResourceNode rn = null; if (n instanceof ResourceNode) { rn = (ResourceNode) n; @@ -145,14 +172,14 @@ DataTransferChannel ch = ((DataFlowEdge) e).getChannel(); for (ChannelMember m: ch.getReferenceChannelMembers()) { if (m.getResource() == cn.getResource()) { - topologicalSort(allNodes, n, visited, orderedList); + topologicalSort(allNodeSets, allNodeSets.get(n), visited, orderedList); } } } } } } - orderedList.add(0, curNode); + orderedList.add(0, curNodeSet); } protected void updateMainComponent(DataTransferModel model, TypeDeclaration mainType, MethodDeclaration mainConstructor, Node componentNode, @@ -245,10 +272,10 @@ } } - protected void declareAccessorInMainComponent(TypeDeclaration mainComponent, ResourcePath accessResId, ILanguageSpecific langSpec) { - MethodDeclaration getter = new MethodDeclaration("get" + langSpec.toComponentName(accessResId.getResourceName()), accessResId.getResourceStateType()); + protected void declareAccessorInMainComponent(TypeDeclaration mainComponent, ResourcePath accessRes, ILanguageSpecific langSpec) { + MethodDeclaration getter = langSpec.newMethodDeclaration("get" + langSpec.toComponentName(accessRes.getResourceName()), accessRes.getResourceStateType()); Block block = new Block(); - block.addStatement(langSpec.getReturnStatement(langSpec.getMethodInvocation(accessResId.getResourceName(), getterOfResourceState)) + langSpec.getStatementDelimiter()); + block.addStatement(langSpec.getReturnStatement(langSpec.getMethodInvocation(accessRes.getResourceName(), getterOfResourceState)) + langSpec.getStatementDelimiter()); getter.setBody(block); mainComponent.addMethod(getter); } diff --git a/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromControlFlowGraph.java b/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromControlFlowGraph.java index 5ec1584..261e4dc 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromControlFlowGraph.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromControlFlowGraph.java @@ -48,7 +48,7 @@ public class CodeGeneratorFromControlFlowGraph extends CodeGenerator { @Override - public void generateCodeFromFlowGraph(DataTransferModel model, IFlowGraph flowGraph, ArrayList components, + public void generateCodeFromFlowGraph(DataTransferModel model, IFlowGraph flowGraph, ArrayList> components, TypeDeclaration mainComponent, MethodDeclaration mainConstructor, ArrayList codes, ILanguageSpecific langSpec) { // Reconstruct data-flow information. Map>> dataFlowInform = new HashMap<>(); @@ -64,32 +64,35 @@ removeRedundantAttributes(root, dataFlowInform); } - // For each of other components. + // For each component other than the main component. Map componentMap = new HashMap<>(); - for (Node componentNode: components) { + for (Set componentNodeSet: components) { // Declare this component. + Node componentNode = componentNodeSet.iterator().next(); String componentName = langSpec.toComponentName(((ObjectNode) componentNode).getName()); TypeDeclaration component = langSpec.newTypeDeclaration(componentName); - componentMap.put(componentNode, component); + for (Node compNode: componentNodeSet) { + componentMap.put(compNode, component); + } // Declare the constructor and the fields to refer to the callee components. List depends = new ArrayList<>(); - MethodDeclaration constructor = declareConstructorAndFieldsToCalleeComponents((ObjectNode) componentNode, component, depends, langSpec); + MethodDeclaration constructor = declareConstructorAndFieldsToCalleeComponents(componentNodeSet, component, depends, langSpec); if (componentNode instanceof StatefulObjectNode) { // For this resource. ResourceNode resourceNode = ((StatefulObjectNode) componentNode).getResource(); - ResourcePath resId = resourceNode.getResource(); - Type resStateType = resId.getResourceStateType(); + ResourcePath res = resourceNode.getResource(); + Type resStateType = res.getResourceStateType(); // Declare the field in this resource to store the state. if (((StoreAttribute) resourceNode.getAttribute()).isStored()) { - FieldDeclaration stateField = langSpec.newFieldDeclaration(resStateType, fieldOfResourceState, langSpec.getFieldInitializer(resStateType, resId.getInitialValue())); + FieldDeclaration stateField = langSpec.newFieldDeclaration(resStateType, fieldOfResourceState, langSpec.getFieldInitializer(resStateType, res.getInitialValue())); component.addField(stateField); } // Declare the accessor method in the main component to call the getter method. - declareAccessorInMainComponent(mainComponent, resId, langSpec); + declareAccessorInMainComponent(mainComponent, res, langSpec); // Declare the fields to refer to reference resources. declareFieldsToReferenceResources(model, resourceNode, component, constructor, depends, langSpec); @@ -242,7 +245,7 @@ } } - private MethodDeclaration declareConstructorAndFieldsToCalleeComponents(ObjectNode componentNode, TypeDeclaration component, + private MethodDeclaration declareConstructorAndFieldsToCalleeComponents(Set componentNodeSet, TypeDeclaration component, List depends, ILanguageSpecific langSpec) { // Declare a constructor in each component. MethodDeclaration constructor = component.createConstructor(); @@ -250,12 +253,14 @@ constructor.setBody(block); // Declare fields in each component. (for control-flow graph) - for (Edge e: componentNode.getOutEdges()) { - ObjectNode dstNode = (ObjectNode) e.getDestination(); - addReference(component, constructor, dstNode, langSpec); - if (dstNode instanceof StatefulObjectNode) { - ResourcePath dstId = ((StatefulObjectNode) dstNode).getResource().getResource(); - if (!depends.contains(dstId)) depends.add(dstId); + for (Node componentNode: componentNodeSet) { + for (Edge e: componentNode.getOutEdges()) { + ObjectNode dstNode = (ObjectNode) e.getDestination(); + addReference(component, constructor, dstNode, langSpec); + if (dstNode instanceof StatefulObjectNode) { + ResourcePath dstRes = ((StatefulObjectNode) dstNode).getResource().getResource(); + if (!depends.contains(dstRes)) depends.add(dstRes); + } } } return constructor; @@ -291,33 +296,33 @@ DataTransferChannel ch = null; HashMap inputResourceToStateAccessor = new HashMap<>(); for (Edge eIn: resourceNode.getInEdges()) { - DataFlowEdge dIn = (DataFlowEdge) eIn; - if (((PushPullAttribute) dIn.getAttribute()).getOptions().get(0) == PushPullValue.PUSH) { + DataFlowEdge dataFlowInEdge = (DataFlowEdge) eIn; + if (((PushPullAttribute) dataFlowInEdge.getAttribute()).getOptions().get(0) == PushPullValue.PUSH) { // PUSH data transfer isContainedPush = true; - inputResourceToStateAccessor.put(((ResourceNode) dIn.getSource()).getResource(), getPushAccessor()); + inputResourceToStateAccessor.put(((ResourceNode) dataFlowInEdge.getSource()).getResource(), getPushAccessor()); } else { // PULL data transfer - for (Edge outEdge: node.getOutEdges()) { + for (Edge callEdge: node.getOutEdges()) { // For each call edge. - ObjectNode dstNode = (ObjectNode) outEdge.getDestination(); - List returnedResources = dataFlowInform.get(outEdge).get(PushPullValue.PULL); - if (returnedResources.contains((ResourceNode) dIn.getSource())) { + ObjectNode calledNode = (ObjectNode) callEdge.getDestination(); + List returnedResources = dataFlowInform.get(callEdge).get(PushPullValue.PULL); + if (returnedResources.contains((ResourceNode) dataFlowInEdge.getSource())) { if (returnedResources.size() == 1) { - MethodDeclaration nextGetter = declareAndFillGetterMethods(dstNode, outEdge, dataFlowInform, componentMap, langSpec); - inputResourceToStateAccessor.put(((ResourceNode) dIn.getSource()).getResource(), getPullAccessor(dstNode.getName(), nextGetter.getName())); + MethodDeclaration nextGetter = declareAndFillGetterMethods(calledNode, callEdge, dataFlowInform, componentMap, langSpec); + inputResourceToStateAccessor.put(((ResourceNode) dataFlowInEdge.getSource()).getResource(), getPullAccessor(calledNode.getName(), nextGetter.getName())); break; } else { - MethodDeclaration nextGetter = declareAndFillGetterMethods(dstNode, outEdge, dataFlowInform, componentMap, langSpec); - int idx = returnedResources.indexOf((ResourceNode) dIn.getSource()); + MethodDeclaration nextGetter = declareAndFillGetterMethods(calledNode, callEdge, dataFlowInform, componentMap, langSpec); + int idx = returnedResources.indexOf((ResourceNode) dataFlowInEdge.getSource()); int len = returnedResources.size(); - inputResourceToStateAccessor.put(((ResourceNode) dIn.getSource()).getResource(), - getPullAccessor(langSpec.getTupleGet(langSpec.getMethodInvocation(langSpec.getFieldAccessor(dstNode.getName()), nextGetter.getName()), idx, len))); + inputResourceToStateAccessor.put(((ResourceNode) dataFlowInEdge.getSource()).getResource(), + getPullAccessor(langSpec.getTupleGet(langSpec.getMethodInvocation(langSpec.getFieldAccessor(calledNode.getName()), nextGetter.getName()), idx, len))); break; } } } - ch = dIn.getChannel(); // Always unique. + ch = dataFlowInEdge.getChannel(); // Always unique. } } // For reference channel members. @@ -354,16 +359,18 @@ // Unexpected. } getterMethodName += langSpec.toComponentName(returnedRes.getResource().getResourceName()) + "Value"; - MethodDeclaration mediateGetter = langSpec.newMethodDeclaration(getterMethodName, returnedRes.getResource().getResourceStateType()); + MethodDeclaration mediateGetter = getMethod(component, getterMethodName); + if (mediateGetter != null) return mediateGetter; + mediateGetter = langSpec.newMethodDeclaration(getterMethodName, returnedRes.getResource().getResourceStateType()); component.addMethod(mediateGetter); // Add a return statement. if (node.getOutdegree() == 1) { - Edge outEdge = node.getOutEdges().iterator().next(); - ObjectNode dstNode = (ObjectNode) outEdge.getDestination(); - MethodDeclaration nextGetter = declareAndFillGetterMethods(dstNode, outEdge, dataFlowInform, componentMap, langSpec); + Edge callEdge = node.getOutEdges().iterator().next(); + ObjectNode calledNode = (ObjectNode) callEdge.getDestination(); + MethodDeclaration nextGetter = declareAndFillGetterMethods(calledNode, callEdge, dataFlowInform, componentMap, langSpec); mediateGetter.addStatement( - langSpec.getReturnStatement(langSpec.getMethodInvocation(langSpec.getFieldAccessor(dstNode.getName()), nextGetter.getName())) + langSpec.getReturnStatement(langSpec.getMethodInvocation(langSpec.getFieldAccessor(calledNode.getName()), nextGetter.getName())) + langSpec.getStatementDelimiter()); } else { // Unexpected. @@ -376,8 +383,10 @@ getterMethodName += langSpec.toComponentName(rn.getResource().getResourceName()); } getterMethodName += "Values"; + MethodDeclaration mediateGetter = getMethod(component, getterMethodName); + if (mediateGetter != null) return mediateGetter; Type returnType = createReturnType(resourcesToReturn, langSpec); - MethodDeclaration mediateGetter = langSpec.newMethodDeclaration(getterMethodName, returnType); + mediateGetter = langSpec.newMethodDeclaration(getterMethodName, returnType); component.addMethod(mediateGetter); // Add a return statement. diff --git a/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromDataFlowGraph.java b/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromDataFlowGraph.java index 4873a2a..4de8146 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromDataFlowGraph.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromDataFlowGraph.java @@ -39,11 +39,12 @@ public class CodeGeneratorFromDataFlowGraph extends CodeGenerator { - public void generateCodeFromFlowGraph(DataTransferModel model, IFlowGraph flowGraph, ArrayList components, + public void generateCodeFromFlowGraph(DataTransferModel model, IFlowGraph flowGraph, ArrayList> components, TypeDeclaration mainComponent, MethodDeclaration mainConstructor, ArrayList codes, ILanguageSpecific langSpec) { // For each of other components. - for (Node componentNode: components) { + for (Set componentNodeSet: components) { // Declare this resource. + Node componentNode = componentNodeSet.iterator().next(); ResourceNode resourceNode = (ResourceNode) componentNode; String resourceName = langSpec.toComponentName(resourceNode.getResource().getResourceName()); TypeDeclaration component = langSpec.newTypeDeclaration(resourceName); @@ -55,12 +56,12 @@ // Update the main component for this component. updateMainComponent(model, mainComponent, mainConstructor, componentNode, depends, langSpec); - ResourcePath resId = resourceNode.getResource(); - Type resStateType = resId.getResourceStateType(); + ResourcePath res = resourceNode.getResource(); + Type resStateType = res.getResourceStateType(); // Declare the field in this resource to store the state. if (((StoreAttribute) resourceNode.getAttribute()).isStored()) { - FieldDeclaration stateField = langSpec.newFieldDeclaration(resStateType, fieldOfResourceState, langSpec.getFieldInitializer(resStateType, resId.getInitialValue())); + FieldDeclaration stateField = langSpec.newFieldDeclaration(resStateType, fieldOfResourceState, langSpec.getFieldInitializer(resStateType, res.getInitialValue())); component.addField(stateField); } @@ -68,7 +69,7 @@ MethodDeclaration getter = declareGetterMethod(resourceNode, component, resStateType, langSpec); // Declare the accessor method in the main component to call the getter method. - declareAccessorInMainComponent(mainComponent, resId, langSpec); + declareAccessorInMainComponent(mainComponent, res, langSpec); // Declare the fields to refer to reference resources. declareFieldsToReferenceResources(model, resourceNode, component, constructor, depends, langSpec); diff --git a/AlgebraicDataflowArchitectureModel/src/generators/ILanguageSpecific.java b/AlgebraicDataflowArchitectureModel/src/generators/ILanguageSpecific.java index 38e4e0a..35e67ce 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/ILanguageSpecific.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/ILanguageSpecific.java @@ -17,9 +17,11 @@ TypeDeclaration newTypeDeclaration(String typeName); VariableDeclaration newVariableDeclaration(Type type, String varName); MethodDeclaration newMethodDeclaration(String methodName, Type returnType); - MethodDeclaration newMethodDeclaration(String methodName, boolean isConstructor, Type returnType, ArrayList parameters); + MethodDeclaration newMethodDeclaration(String methodName, boolean isConstructor, Type returnType, List parameters); FieldDeclaration newFieldDeclaration(Type fieldType, String fieldName); FieldDeclaration newFieldDeclaration(Type fieldType, String fieldName, String fieldInitializer); + Type newListType(String compTypeName); + Type newMapType(Type keyType, String compTypeName); Type newTupleType(List compTypes); String getVariableDeclaration(String typeName, String varName); String getFieldInitializer(Type type, Expression initialValue); @@ -31,6 +33,7 @@ String getConstructorInvocation(String componentName, List parameters); String getReturnStatement(String returnValue); String toComponentName(String name); + String toVariableName(String name); String getMainComponentName(); String getTupleGet(String tupleExp, int idx, int length); String getDecomposedTuple(String tupleExp, VariableDeclaration tupleVar, List vars); diff --git a/AlgebraicDataflowArchitectureModel/src/generators/JavaCodeGenerator.java b/AlgebraicDataflowArchitectureModel/src/generators/JavaCodeGenerator.java index 585754a..34590cf 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/JavaCodeGenerator.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/JavaCodeGenerator.java @@ -111,13 +111,13 @@ } } Set refs = new HashSet<>(); - for (Channel cg : model.getChannels()) { - DataTransferChannel c = (DataTransferChannel) cg; + for (Channel ch : model.getChannels()) { + DataTransferChannel c = (DataTransferChannel) ch; if (c.getInputResources().contains(rn.getResource())) { - for (ResourcePath id: c.getReferenceResources()) { - if (!refs.contains(id) && !depends.contains(id)) { - refs.add(id); - String refResName = id.getResourceName(); + for (ResourcePath res: c.getReferenceResources()) { + if (!refs.contains(res) && !depends.contains(res)) { + refs.add(res); + String refResName = res.getResourceName(); fieldInitializer += refResName.toLowerCase() + ","; f = true; } @@ -128,12 +128,12 @@ fieldInitializer += ")"; FieldDeclaration field = new FieldDeclaration(new Type(resourceName, resourceName), rn.getResource().getResourceName()); mainType.addField(field); - Block manConstructorBody = mainConstructor.getBody(); - if (manConstructorBody == null) { - manConstructorBody = new Block(); - mainConstructor.setBody(manConstructorBody); + Block mainConstructorBody = mainConstructor.getBody(); + if (mainConstructorBody == null) { + mainConstructorBody = new Block(); + mainConstructor.setBody(mainConstructorBody); } - manConstructorBody.addStatement(rn.getResource().getResourceName() + " = " + fieldInitializer + ";"); + mainConstructorBody.addStatement(rn.getResource().getResourceName() + " = " + fieldInitializer + ";"); // Declare a constructor, fields and update methods in the type of each resource. MethodDeclaration constructor = new MethodDeclaration(resourceName, true); @@ -176,17 +176,17 @@ } // Declare a field to refer to the reference resource. refs = new HashSet<>(); - for (Channel cg : model.getChannels()) { - DataTransferChannel c = (DataTransferChannel) cg; + for (Channel ch : model.getChannels()) { + DataTransferChannel c = (DataTransferChannel) ch; if (c.getInputResources().contains(rn.getResource())) { - for (ResourcePath id: c.getReferenceResources()) { - if (!refs.contains(id) && !depends.contains(id)) { - refs.add(id); - String refResName = id.getResourceName(); + for (ResourcePath res: c.getReferenceResources()) { + if (!refs.contains(res) && !depends.contains(res)) { + refs.add(res); + String refResName = res.getResourceName(); refResName = refResName.substring(0, 1).toUpperCase() + refResName.substring(1); - type.addField(new FieldDeclaration(new Type(refResName, refResName), id.getResourceName())); - constructor.addParameter(new VariableDeclaration(new Type(refResName, refResName), id.getResourceName())); - block.addStatement("this." + id.getResourceName() + " = " + id.getResourceName() + ";"); + type.addField(new FieldDeclaration(new Type(refResName, refResName), res.getResourceName())); + constructor.addParameter(new VariableDeclaration(new Type(refResName, refResName), res.getResourceName())); + block.addStatement("this." + res.getResourceName() + " = " + res.getResourceName() + ";"); } } } @@ -196,11 +196,11 @@ type.addMethod(constructor); // Declare input methods in resources and the main type. - for (Channel cg : model.getIOChannels()) { - for (ChannelMember cm : ((DataTransferChannel) cg).getOutputChannelMembers()) { + for (Channel ch : model.getIOChannels()) { + for (ChannelMember cm : ((DataTransferChannel) ch).getOutputChannelMembers()) { if (cm.getResource().equals(rn.getResource())) { Expression message = cm.getStateTransition().getMessageExpression(); - if (message.getClass() == Term.class) { + if (message instanceof Term) { ArrayList params = new ArrayList<>(); for (Variable var: message.getVariables().values()) { params.add(new VariableDeclaration(var.getType(), var.getName())); @@ -226,7 +226,7 @@ } } } - } else if (message.getClass() == Variable.class) { + } else if (message instanceof Variable) { MethodDeclaration input = new MethodDeclaration( ((Variable) cm.getStateTransition().getMessageExpression()).getName(), false, typeVoid, null); @@ -244,8 +244,8 @@ // Declare the field to store the state in the type of each resource. if (((StoreAttribute) rn.getAttribute()).isStored()) { - ResourcePath resId = rn.getResource(); - type.addField(new FieldDeclaration(resId.getResourceStateType(), "value", getInitializer(resId))); + ResourcePath res = rn.getResource(); + type.addField(new FieldDeclaration(res.getResourceStateType(), "value", getInitializer(res))); } // Declare the getter method to obtain the state in the type of each resource. diff --git a/AlgebraicDataflowArchitectureModel/src/generators/JavaSpecific.java b/AlgebraicDataflowArchitectureModel/src/generators/JavaSpecific.java index 0176b5e..f9ffe2c 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/JavaSpecific.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/JavaSpecific.java @@ -46,7 +46,7 @@ } @Override - public MethodDeclaration newMethodDeclaration(String methodName, boolean isConstructor, Type returnType, ArrayList parameters) { + public MethodDeclaration newMethodDeclaration(String methodName, boolean isConstructor, Type returnType, List parameters) { if (returnType == null) { returnType = typeVoid; } @@ -64,6 +64,16 @@ } @Override + public Type newListType(String compTypeName) { + return new Type("List", "ArrayList<>", "List<" + compTypeName + ">", DataConstraintModel.typeList); + } + + @Override + public Type newMapType(Type keyType, String valueTypeName) { + return new Type("Map", "HashMap<>", "Map<" + keyType.getImplementationTypeName() + ", " + valueTypeName + ">", DataConstraintModel.typeMap); + } + + @Override public Type newTupleType(List componentTypes) { String implTypeName = "AbstractMap.SimpleEntry<>"; String interfaceTypeName = "Map.Entry<$x>"; @@ -169,6 +179,11 @@ } @Override + public String toVariableName(String name) { + return name.substring(0, 1).toLowerCase() + name.substring(1); + } + + @Override public String getMainComponentName() { return "Main"; } diff --git a/AlgebraicDataflowArchitectureModel/src/generators/JerseyCodeGenerator.java b/AlgebraicDataflowArchitectureModel/src/generators/JerseyCodeGenerator.java index 20f61f7..d191a18 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/JerseyCodeGenerator.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/JerseyCodeGenerator.java @@ -149,11 +149,11 @@ // } // Declare input methods in resources. - for (Channel cg : model.getIOChannels()) { - for (ChannelMember cm : ((DataTransferChannel) cg).getOutputChannelMembers()) { + for (Channel ch : model.getIOChannels()) { + for (ChannelMember cm : ((DataTransferChannel) ch).getOutputChannelMembers()) { if (cm.getResource().equals(rn.getResource())) { Expression message = cm.getStateTransition().getMessageExpression(); - if (message.getClass() == Term.class) { + if (message instanceof Term) { ArrayList params = new ArrayList<>(); for (Variable var: message.getVariables().values()) { String paramName = var.getName(); @@ -170,7 +170,7 @@ input.addAnnotation(new Annotation("POST")); } type.addMethod(input); - } else if (message.getClass() == Variable.class) { + } else if (message instanceof Variable) { MethodDeclaration input = new MethodDeclaration( ((Variable) cm.getStateTransition().getMessageExpression()).getName(), false, typeVoid, null); @@ -187,8 +187,8 @@ // Declare the field to store the state in the type of each resource. if (((StoreAttribute) rn.getAttribute()).isStored()) { - ResourcePath resId = rn.getResource(); - type.addField(new FieldDeclaration(resId.getResourceStateType(), "value", getInitializer(resId))); + ResourcePath res = rn.getResource(); + type.addField(new FieldDeclaration(res.getResourceStateType(), "value", getInitializer(res))); } // Declare the getter method to obtain the state in the type of each resource. diff --git a/AlgebraicDataflowArchitectureModel/src/models/algebra/Term.java b/AlgebraicDataflowArchitectureModel/src/models/algebra/Term.java index a16fac5..81b24ed 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/algebra/Term.java +++ b/AlgebraicDataflowArchitectureModel/src/models/algebra/Term.java @@ -327,7 +327,12 @@ } if (getArity() >= 1 && symbol.isImplMethod()) { if (implParamOrder == null) { - String exp = children.get(0).toImplementation(sideEffects) + "." + symbol.toImplementation() + "("; + String exp = null; + if (children.get(0) != null) { + exp = children.get(0).toImplementation(sideEffects) + "." + symbol.toImplementation() + "("; + } else { + exp = symbol.toImplementation() + "("; + } String delimiter = ""; for (int i = 1; i < children.size(); i++) { Expression e = children.get(i); @@ -337,7 +342,11 @@ exp += ")"; if (symbol.isImplWithSideEffect()) { sideEffects[0] = sideEffects[0] + exp + ";\n"; - exp = children.get(0).toImplementation(new String[] {""}); + if (children.get(0) != null) { + exp = children.get(0).toImplementation(new String[] {""}); + } else { + exp = ""; + } } return exp; } else { 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/controlFlowModel/ControlFlowGraph.java b/AlgebraicDataflowArchitectureModel/src/models/controlFlowModel/ControlFlowGraph.java index 2913494..c2f9477 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/controlFlowModel/ControlFlowGraph.java +++ b/AlgebraicDataflowArchitectureModel/src/models/controlFlowModel/ControlFlowGraph.java @@ -1,6 +1,9 @@ package models.controlFlowModel; +import java.util.Collection; +import java.util.HashMap; import java.util.HashSet; +import java.util.Map; import java.util.Set; import models.Edge; @@ -108,18 +111,31 @@ } @Override - public Set getAllNodes() { - Set allNodes = new HashSet<>(); - allNodes.addAll(pushCallGraph.getNodes()); + public Map> getAllNodes() { + Map> allNodeSets = new HashMap<>(); + for (Node n: pushCallGraph.getNodes()) { + Set nodeSet = new HashSet<>(); + nodeSet.add(n); + allNodeSets.put(n, nodeSet); + } for (Node n: pullCallGraph.getNodes()) { if (n instanceof StatefulObjectNode) { - if (pushCallGraph.getStatefulObjectNode(((StatefulObjectNode) n).getResource()) == null) { - allNodes.add(n); + ResourceNode resNode = ((StatefulObjectNode) n).getResource(); + Set nodeSet = null; + if (pushCallGraph.getStatefulObjectNode(resNode) != null) { + // Merge a stateful object node in the push call graph and that in the pull call graph. + nodeSet = allNodeSets.get(pushCallGraph.getStatefulObjectNode(resNode)); + } else { + nodeSet = new HashSet<>(); } + nodeSet.add(n); + allNodeSets.put(n, nodeSet); } else { - allNodes.add(n); + Set nodeSet = new HashSet<>(); + nodeSet.add(n); + allNodeSets.put(n, nodeSet); } } - return allNodes; + return allNodeSets; } } diff --git a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/DataConstraintModel.java b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/DataConstraintModel.java index aa6cee8..5adffa7 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/DataConstraintModel.java +++ b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/DataConstraintModel.java @@ -31,9 +31,10 @@ public static final Type typePairInt = new Type("Pair", "Pair", "Pair", typePair); public static final Type typePairStr = new Type("Pair", "Pair", "Pair", typePair); public static final Type typePairDouble = new Type("Pair", "Pair", "Pair", typePair); - public static final Type typeMap = new Type("Map", "HashMap", "Map"); + public static final 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); @@ -147,6 +148,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); @@ -198,6 +203,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}); @@ -233,6 +242,7 @@ addType(typePair); addType(typeTuple); addType(typeMap); + addType(typeJson); symbols = new HashMap<>(); addSymbol(add); addSymbol(mul); @@ -269,6 +279,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..e591e07 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/JsonAccessor.java @@ -0,0 +1,142 @@ +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) return valueType; + } + 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/dataFlowModel/DataFlowGraph.java b/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/DataFlowGraph.java index 2a7660d..1b3a208 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/DataFlowGraph.java +++ b/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/DataFlowGraph.java @@ -2,6 +2,7 @@ import java.util.Collection; import java.util.HashMap; +import java.util.HashSet; import java.util.Map; import java.util.Set; @@ -51,7 +52,13 @@ } @Override - public Set getAllNodes() { - return super.getNodes(); + public Map> getAllNodes() { + Map> allNodeSets = new HashMap<>(); + for (Node n: super.getNodes()) { + Set nodeSet = new HashSet<>(); + nodeSet.add(n); + allNodeSets.put(n, nodeSet); + } + return allNodeSets; } } diff --git a/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/IFlowGraph.java b/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/IFlowGraph.java index 141c81f..d159bd7 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/IFlowGraph.java +++ b/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/IFlowGraph.java @@ -1,9 +1,10 @@ package models.dataFlowModel; +import java.util.Map; import java.util.Set; import models.Node; public interface IFlowGraph { - abstract public Set getAllNodes(); + abstract public Map> getAllNodes(); } diff --git a/AlgebraicDataflowArchitectureModel/src/parser/Parser.java b/AlgebraicDataflowArchitectureModel/src/parser/Parser.java index 3713e9a..d74da73 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.ResourcePath; import models.dataConstraintModel.StateTransition; import models.dataFlowModel.DataTransferModel; @@ -27,6 +28,7 @@ import parser.exceptions.ExpectedRHSExpression; import parser.exceptions.ExpectedRightBracket; import parser.exceptions.ExpectedStateTransition; +import parser.exceptions.WrongJsonExpression; import parser.exceptions.WrongLHSExpression; import parser.exceptions.WrongRHSExpression; @@ -59,7 +61,8 @@ public static final String ASSIGNMENT = "="; public static final String COMMA = ","; public static final String COLON = ":"; - + public static final String DOT = "."; + public static final String DOT_REGX = "\\."; public Parser(final TokenStream stream) { this.stream = stream; @@ -79,12 +82,14 @@ } public DataTransferModel doParse() - throws ExpectedRightBracket, ExpectedChannel, ExpectedChannelName, ExpectedLeftCurlyBracket, ExpectedInOrOutOrRefKeyword, ExpectedStateTransition, ExpectedEquals, ExpectedRHSExpression, WrongLHSExpression, WrongRHSExpression, ExpectedAssignment { + throws ExpectedRightBracket, ExpectedChannel, ExpectedChannelName, ExpectedLeftCurlyBracket, ExpectedInOrOutOrRefKeyword, + ExpectedStateTransition, ExpectedEquals, ExpectedRHSExpression, WrongLHSExpression, WrongRHSExpression, ExpectedAssignment, WrongJsonExpression { return parseDataFlowModel(); } public DataTransferModel parseDataFlowModel() - throws ExpectedRightBracket, ExpectedChannel, ExpectedChannelName, ExpectedLeftCurlyBracket, ExpectedInOrOutOrRefKeyword, ExpectedStateTransition, ExpectedEquals, ExpectedRHSExpression, WrongLHSExpression, WrongRHSExpression, ExpectedAssignment { + throws ExpectedRightBracket, ExpectedChannel, ExpectedChannelName, ExpectedLeftCurlyBracket, ExpectedInOrOutOrRefKeyword, + ExpectedStateTransition, ExpectedEquals, ExpectedRHSExpression, WrongLHSExpression, WrongRHSExpression, ExpectedAssignment, WrongJsonExpression { DataTransferModel model = new DataTransferModel(); DataTransferChannel channel; while ((channel = parseChannel(model)) != null) { @@ -102,7 +107,7 @@ ExpectedLeftCurlyBracket, ExpectedRightBracket, ExpectedAssignment, ExpectedRHSExpression, WrongLHSExpression, WrongRHSExpression, ExpectedChannel, ExpectedChannelName, ExpectedInOrOutOrRefKeyword, - ExpectedStateTransition, ExpectedEquals + ExpectedStateTransition, ExpectedEquals, WrongJsonExpression { if (!stream.hasNext()) return null; if (stream.checkNext().equals(RIGHT_CURLY_BRACKET)) return null; @@ -152,7 +157,7 @@ public void parseInit(DataTransferModel model) throws - ExpectedLeftCurlyBracket, ExpectedAssignment, ExpectedRHSExpression, WrongRHSExpression, ExpectedRightBracket + ExpectedLeftCurlyBracket, ExpectedAssignment, ExpectedRHSExpression, WrongRHSExpression, ExpectedRightBracket, WrongJsonExpression { String leftBracket = stream.next(); if (!leftBracket.equals(LEFT_CURLY_BRACKET)) throw new ExpectedLeftCurlyBracket(stream.getLine()); @@ -186,7 +191,7 @@ public ChannelMember parseChannelMember(DataTransferModel model, final String inOrOutOrRef) throws ExpectedRightBracket, ExpectedStateTransition, ExpectedEquals, - ExpectedRHSExpression, WrongLHSExpression, WrongRHSExpression + ExpectedRHSExpression, WrongLHSExpression, WrongRHSExpression, WrongJsonExpression { if (!stream.hasNext()) throw new ExpectedStateTransition(stream.getLine()); Expression leftTerm = parseTerm(stream, model); @@ -240,7 +245,7 @@ } public Expression parseTerm(TokenStream stream, DataTransferModel model) - throws ExpectedRightBracket + throws ExpectedRightBracket, WrongJsonExpression { ArrayList expressions = new ArrayList<>(); ArrayList operators = new ArrayList<>(); @@ -283,31 +288,29 @@ symbol.setArity(arity); exp = term; } else { - // constant or variable - try { - Symbol symbol = model.getSymbol(symbolName); - if (symbol != null && symbol.getArity() == 0) { - 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); - if (symbolName.contains(".")) { + // a numerical value + if (symbolName.contains(DOT)) { exp = new Constant(symbolName, DataTransferModel.typeDouble); } else { exp = new Constant(symbolName, DataTransferModel.typeInt); } - } - } catch (NumberFormatException e) { - if (stream.checkNext() != null && stream.checkNext().equals(COLON)) { - // when a type is specified. - stream.next(); - String typeName = stream.next(); - Type type = model.getType(typeName); - if (type == null) { - type = new Type(typeName, typeName); - } - exp = new Variable(symbolName, type); } else { - exp = new Variable(symbolName); + // a variable + exp = parseVariable(stream, model, symbolName); } } } @@ -324,16 +327,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 @@ -372,6 +411,23 @@ return firstMonomial; } + private Variable parseVariable(TokenStream stream, DataTransferModel model, String symbolName) { + Variable var; + if (stream.checkNext() != null && stream.checkNext().equals(COLON)) { + // when a type is specified. + stream.next(); + String typeName = stream.next(); + Type type = model.getType(typeName); + if (type == null) { + type = new Type(typeName, typeName); + } + var = new Variable(symbolName, type); + } else { + var = new Variable(symbolName); + } + return var; + } + /**-------------------------------------------------------------------------------- * [protected] /**-------------------------------------------------------------------------------- @@ -416,15 +472,18 @@ splitBy( splitBy( splitBy( - Arrays.asList(line.split("[ \t]")), - ADD, - ADD_REGX), - MUL, - MUL_REGX), - SUB, - SUB_REGX), - DIV, - DIV_REGX), + splitBy( + Arrays.asList(line.split("[ \t]")), + ADD, + ADD_REGX), + MUL, + MUL_REGX), + SUB, + SUB_REGX), + DIV, + DIV_REGX), + DOT, + DOT_REGX), COMMA, COMMA), COLON, diff --git a/AlgebraicDataflowArchitectureModel/src/parser/ParserDTRAM.java b/AlgebraicDataflowArchitectureModel/src/parser/ParserDTRAM.java index 54d0bf1..6330de2 100644 --- a/AlgebraicDataflowArchitectureModel/src/parser/ParserDTRAM.java +++ b/AlgebraicDataflowArchitectureModel/src/parser/ParserDTRAM.java @@ -27,6 +27,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; @@ -62,9 +63,10 @@ /**-------------------------------------------------------------------------------- * * @param reader + * @throws WrongJsonExpression */ public DataTransferModel doParseModel() - throws ExpectedRightBracket, ExpectedChannel, ExpectedChannelName, ExpectedLeftCurlyBracket, ExpectedInOrOutOrRefKeyword, ExpectedStateTransition, ExpectedEquals, ExpectedRHSExpression, WrongLHSExpression, WrongRHSExpression, ExpectedAssignment, ExpectedModel, ExpectedGeometry { + throws ExpectedRightBracket, ExpectedChannel, ExpectedChannelName, ExpectedLeftCurlyBracket, ExpectedInOrOutOrRefKeyword, ExpectedStateTransition, ExpectedEquals, ExpectedRHSExpression, WrongLHSExpression, WrongRHSExpression, ExpectedAssignment, ExpectedModel, ExpectedGeometry, WrongJsonExpression { DataTransferModel model = getParsedModel(); return model; } @@ -84,9 +86,10 @@ /**-------------------------------------------------------------------------------- * * @param stream + * @throws WrongJsonExpression */ private DataTransferModel getParsedModel() - throws ExpectedRightBracket, ExpectedChannel, ExpectedChannelName, ExpectedLeftCurlyBracket, ExpectedInOrOutOrRefKeyword, ExpectedStateTransition, ExpectedEquals, ExpectedRHSExpression, WrongLHSExpression, WrongRHSExpression, ExpectedAssignment, ExpectedModel, ExpectedGeometry { + throws ExpectedRightBracket, ExpectedChannel, ExpectedChannelName, ExpectedLeftCurlyBracket, ExpectedInOrOutOrRefKeyword, ExpectedStateTransition, ExpectedEquals, ExpectedRHSExpression, WrongLHSExpression, WrongRHSExpression, ExpectedAssignment, ExpectedModel, ExpectedGeometry, 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 a89ea3c..54adfc7 100644 --- a/AlgebraicDataflowArchitectureModel/src/tests/CodeGeneratorTest.java +++ b/AlgebraicDataflowArchitectureModel/src/tests/CodeGeneratorTest.java @@ -23,6 +23,7 @@ import parser.exceptions.ExpectedRHSExpression; import parser.exceptions.ExpectedRightBracket; import parser.exceptions.ExpectedStateTransition; +import parser.exceptions.WrongJsonExpression; import parser.exceptions.WrongLHSExpression; import parser.exceptions.WrongRHSExpression; @@ -41,7 +42,7 @@ System.out.println(codetree); } catch (ExpectedChannel | ExpectedChannelName | ExpectedLeftCurlyBracket | ExpectedInOrOutOrRefKeyword | ExpectedStateTransition | ExpectedEquals | ExpectedRHSExpression | WrongLHSExpression - | WrongRHSExpression | ExpectedRightBracket | ExpectedAssignment e) { + | WrongRHSExpression | ExpectedRightBracket | ExpectedAssignment | WrongJsonExpression e) { e.printStackTrace(); } } catch (FileNotFoundException e) { diff --git a/AlgebraicDataflowArchitectureModel/src/tests/DataStorageDecisionTest.java b/AlgebraicDataflowArchitectureModel/src/tests/DataStorageDecisionTest.java index 9d28936..e1cbbf4 100644 --- a/AlgebraicDataflowArchitectureModel/src/tests/DataStorageDecisionTest.java +++ b/AlgebraicDataflowArchitectureModel/src/tests/DataStorageDecisionTest.java @@ -19,6 +19,7 @@ import parser.exceptions.ExpectedRHSExpression; import parser.exceptions.ExpectedRightBracket; import parser.exceptions.ExpectedStateTransition; +import parser.exceptions.WrongJsonExpression; import parser.exceptions.WrongLHSExpression; import parser.exceptions.WrongRHSExpression; @@ -39,7 +40,7 @@ } } catch (ExpectedChannel | ExpectedChannelName | ExpectedLeftCurlyBracket | ExpectedInOrOutOrRefKeyword | ExpectedStateTransition | ExpectedEquals | ExpectedRHSExpression | WrongLHSExpression - | WrongRHSExpression | ExpectedRightBracket | ExpectedAssignment e) { + | WrongRHSExpression | ExpectedRightBracket | ExpectedAssignment | WrongJsonExpression e) { e.printStackTrace(); } } catch (FileNotFoundException e) { diff --git a/AlgebraicDataflowArchitectureModel/src/tests/DataStorageNecessityTest.java b/AlgebraicDataflowArchitectureModel/src/tests/DataStorageNecessityTest.java index 9a7c300..7e9630d 100644 --- a/AlgebraicDataflowArchitectureModel/src/tests/DataStorageNecessityTest.java +++ b/AlgebraicDataflowArchitectureModel/src/tests/DataStorageNecessityTest.java @@ -18,6 +18,7 @@ import parser.exceptions.ExpectedRHSExpression; import parser.exceptions.ExpectedRightBracket; import parser.exceptions.ExpectedStateTransition; +import parser.exceptions.WrongJsonExpression; import parser.exceptions.WrongLHSExpression; import parser.exceptions.WrongRHSExpression; @@ -39,7 +40,7 @@ } } catch (ExpectedChannel | ExpectedChannelName | ExpectedLeftCurlyBracket | ExpectedInOrOutOrRefKeyword | ExpectedStateTransition | ExpectedEquals | ExpectedRHSExpression | WrongLHSExpression - | WrongRHSExpression | ExpectedRightBracket | ExpectedAssignment e) { + | WrongRHSExpression | ExpectedRightBracket | ExpectedAssignment | WrongJsonExpression e) { e.printStackTrace(); } } catch (FileNotFoundException e) { diff --git a/AlgebraicDataflowArchitectureModel/src/tests/EdgeTransitionSelectableTest.java b/AlgebraicDataflowArchitectureModel/src/tests/EdgeTransitionSelectableTest.java index 847fb6f..df97097 100644 --- a/AlgebraicDataflowArchitectureModel/src/tests/EdgeTransitionSelectableTest.java +++ b/AlgebraicDataflowArchitectureModel/src/tests/EdgeTransitionSelectableTest.java @@ -18,6 +18,7 @@ import parser.exceptions.ExpectedRHSExpression; import parser.exceptions.ExpectedRightBracket; import parser.exceptions.ExpectedStateTransition; +import parser.exceptions.WrongJsonExpression; import parser.exceptions.WrongLHSExpression; import parser.exceptions.WrongRHSExpression; @@ -38,7 +39,7 @@ } } catch (ExpectedChannel | ExpectedChannelName | ExpectedLeftCurlyBracket | ExpectedInOrOutOrRefKeyword | ExpectedStateTransition | ExpectedEquals | ExpectedRHSExpression | WrongLHSExpression - | WrongRHSExpression | ExpectedRightBracket | ExpectedAssignment e) { + | WrongRHSExpression | ExpectedRightBracket | ExpectedAssignment | 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 5f51af7..9ce5439 100644 --- a/AlgebraicDataflowArchitectureModel/src/tests/UpdateConflictCheckTest.java +++ b/AlgebraicDataflowArchitectureModel/src/tests/UpdateConflictCheckTest.java @@ -17,6 +17,7 @@ import parser.exceptions.ExpectedRHSExpression; import parser.exceptions.ExpectedRightBracket; import parser.exceptions.ExpectedStateTransition; +import parser.exceptions.WrongJsonExpression; import parser.exceptions.WrongLHSExpression; import parser.exceptions.WrongRHSExpression; @@ -61,6 +62,9 @@ } catch (ExpectedAssignment e) { // TODO Auto-generated catch block e.printStackTrace(); + } catch (WrongJsonExpression e) { + // TODO Auto-generated catch block + e.printStackTrace(); } } catch (FileNotFoundException e) { e.printStackTrace(); diff --git a/AlgebraicDataflowArchitectureModel/src/tests/parser/ParseTest.java b/AlgebraicDataflowArchitectureModel/src/tests/parser/ParseTest.java index a1ea0a3..790d6ae 100644 --- a/AlgebraicDataflowArchitectureModel/src/tests/parser/ParseTest.java +++ b/AlgebraicDataflowArchitectureModel/src/tests/parser/ParseTest.java @@ -23,6 +23,7 @@ import parser.exceptions.ExpectedRHSExpression; import parser.exceptions.ExpectedRightBracket; import parser.exceptions.ExpectedStateTransition; +import parser.exceptions.WrongJsonExpression; import parser.exceptions.WrongLHSExpression; import parser.exceptions.WrongRHSExpression; @@ -54,7 +55,7 @@ | ExpectedStateTransition | ExpectedEquals | ExpectedRHSExpression | WrongLHSExpression | WrongRHSExpression | ExpectedRightBracket | ParameterizedIdentifierIsFutureWork | ResolvingMultipleDefinitionIsFutureWork | InvalidMessage - | UnificationFailed | ValueUndefined | ExpectedAssignment e) { + | UnificationFailed | ValueUndefined | ExpectedAssignment | WrongJsonExpression e) { e.printStackTrace(); } } catch (FileNotFoundException e) {