diff --git a/AlgebraicDataflowArchitectureModel/models/CustomerOffice.model b/AlgebraicDataflowArchitectureModel/models/CustomerOffice.model index 42cdf13..5714436 100644 --- a/AlgebraicDataflowArchitectureModel/models/CustomerOffice.model +++ b/AlgebraicDataflowArchitectureModel/models/CustomerOffice.model @@ -1,21 +1,21 @@ -channel CIO_AddCustomer { - out customers(db:Map, addCustomer(uid:Str, off:Str)) = insert(db, uid, {"off": off}) +channel AddCustomer { + out customers(csDB:Map, addCustomer(uid:Str, office:Str)) = insert(csDB, uid, {"office": office}) } -channel CIO_AddCampany { - out companies(db:Map, addCampany(cid:Str, add:Str)) = insert(db, cid, {"add": add}) +channel AddCampany { + out companies(cmDB:Map, addCampany(cid:Str, address:Str)) = insert(cmDB, cid, {"address": address}) } -channel CIO_SetCustomerOff(uid:Str) { - out customers.{uid}.off(cid:Str, setOff(cid2)) = cid2 +channel SetCustomerOffice(uid:Str) { + out customers.{uid}.office(prevCid:Str, setOffice(cid)) = cid } -channel CIO_SetCompanyAdd(cid:Str) { - out companies.{cid}.add(a1:Str, setAdd(a2)) = a2 +channel SetCompanyAddress(cid:Str) { + out companies.{cid}.address(prevAdd:Str, setAddress(add)) = add } -channel C(uid:Str) { - in customers.{uid}.off(cid, sync(cid2, add2)) = cid2 - in companies.{cid2}.add(a1, sync(cid2, add2)) = add2 - out customers.{uid}.add(a3:Str, sync(cid2, add2)) = add2 +channel UpdateCustomerAddress(uid:Str) { + in customers.{uid}.office(prevCid, updateCustomerAddress(cid, add)) = cid + in companies.{cid}.address(prevAdd, updateCustomerAddress(cid, add)) = add + out customers.{uid}.address(prevAdd, updateCustomerAddress(cid, add)) = add } diff --git a/AlgebraicDataflowArchitectureModel/models/GroupChat.model b/AlgebraicDataflowArchitectureModel/models/GroupChat.model new file mode 100644 index 0000000..634ddf0 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/models/GroupChat.model @@ -0,0 +1,27 @@ +channel Signup { + out accounts(acDB:Map, signUp(aid:Str)) = insert(acDB, aid, {"notifications": nil}) +} + +channel HasRead(aid:Str) { + out accounts.{aid}.notifications(ntMap:Map, hasRead(gid:Str)) = delete(ntMap, gid) +} + +channel CreateGroup { + out groups(grDB:Map, createGroup(gid:Str)) = insert(grDB, gid, {"members": nil, "messages": nil}) +} + +channel AddGroupMember(gid:Str) { + out groups.{gid}.members(memList:List, addGroupMember(aid:Str)) = append(memList, aid) +} + +channel PostMessage(gid:Str) { + out groups.{gid}.messages(mesList:List, postMessage(message:Str)) = append(mesList, message) +} + +channel Notify(gid:Str) { + in groups.{gid}.messages(prevMesList, notify(m)) = mesList + for EachMember(mno:Int) { + ref groups.{gid}.members.{mno}(m.{mno}:Str, notify(m)) + out accounts.{m.{mno}}.notifications(prevNtMap:Map, notify(m)) = insert(prevNtMap, gid, true) + } +} diff --git a/AlgebraicDataflowArchitectureModel/models/OnlineBattleGame.model b/AlgebraicDataflowArchitectureModel/models/OnlineBattleGame.model index 846ffbf..d91b144 100644 --- a/AlgebraicDataflowArchitectureModel/models/OnlineBattleGame.model +++ b/AlgebraicDataflowArchitectureModel/models/OnlineBattleGame.model @@ -1,31 +1,31 @@ -channel CIO_Signup{ - out accounts(adb:Map, signUp(aid:Str, name:Str)) = insert(adb, aid, {"name": name}) +channel Signup { + out accounts(acDB:Map, signUp(aid:Str, name:Str)) = insert(acDB, aid, {"name": name}) } -channel CIO_ChangeName(aid:Str) { - out accounts.{aid}.name(prev_name:Str, changeName(name)) = name +channel ChangeName(aid:Str) { + out accounts.{aid}.name(prevName:Str, changeName(name)) = name } -channel CIO_CreateRoom { - out rooms(rdb:Map, createRoom(rid:Str, blue_id:Str, red_id:Str)) = insert(rdb, rid, {"blue_id": blue_id, "red_id": red_id}) +channel CreateRoom { + out rooms(rmDB:Map, createRoom(rid:Str, blueId:Str, redId:Str)) = insert(rmDB, rid, {"blue_id": blueId, "red_id": redId}) } -channel CIO_ChangeRed_id(rid:Str) { - out rooms.{rid}.red_id(prev_red_id:Str, changeRed_id(red_id)) = red_id +channel ChangeRedId(rid:Str) { + out rooms.{rid}.red_id(prevRedId:Str, changeRedId(redId)) = redId } -channel CIO_ChangeBlue_id(rid:Str) { - out rooms.{rid}.blue_id(prev_blue_id:Str, changeBlue_id(blue_id)) = blue_id +channel ChangeBlueId(rid:Str) { + out rooms.{rid}.blue_id(prevBlueId:Str, changeBlueId(blueId)) = blueId } -channel C_red(rid:Str) { - in rooms.{rid}.red_id(prev_aid:Str, sync(aid, name)) = aid - in accounts.{aid}.name(prev_name:Str, sync(aid, name)) = name - out rooms.{rid}.red_name(prev_name:Str, sync(aid, name)) = name +channel UpdateRedName(rid:Str) { + in rooms.{rid}.red_id(prevAid:Str, updateRedName(aid, name)) = aid + in accounts.{aid}.name(prevName:Str, updateRedName(aid, name)) = name + out rooms.{rid}.red_name(prevName:Str, updateRedName(aid, name)) = name } -channel C_blue(rid:Str) { - in rooms.{rid}.blue_id(prev_aid:Str, sync(aid, name)) = aid - in accounts.{aid}.name(prev_name:Str, sync(aid, name)) = name - out rooms.{rid}.blue_name(prev_name:Str, sync(aid, name)) = name +channel UpdateBlueName(rid:Str) { + in rooms.{rid}.blue_id(prevAid:Str, updateBlueName(aid, name)) = aid + in accounts.{aid}.name(prevName:Str, updateBlueName(aid, name)) = name + out rooms.{rid}.blue_name(prevName:Str, updateBlueName(aid, name)) = name } \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/models/OnlineBattleGame2.model b/AlgebraicDataflowArchitectureModel/models/OnlineBattleGame2.model new file mode 100644 index 0000000..291c9eb --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/models/OnlineBattleGame2.model @@ -0,0 +1,33 @@ +channel Signup { + out accounts(acDB:Map, signUp(aid:Str, name:Str)) = insert(acDB, aid, {"name": name, "point": 0}) +} + +channel ChangeName(aid:Str) { + out accounts.{aid}.name(prevName:Str, changeName(name)) = name +} + +channel CreateRoom { + out rooms(rmDB:Map, createRoom(rid:Str)) = insert(rmDB, rid, {"members": nil, "battle": false}) +} + +channel AddRoomMember(rid:Str) { + out rooms.{rid}.members(mList:List, addRoomMember(id:Str)) = append(mList, {"id": id}) +} + +channel Battle(rid:Str) { + out rooms.{rid}.battle(prevHasWon, battle(hasWon:Bool)) = hasWon +} + +channel UpdateName(rid:Str, mno:Int) { + in rooms.{rid}.members.{mno}.id(prevMid:Str, updateName(mid, name)) = mid + in accounts.{mid}.name(prevName:Str, updateName(mid, name)) = name + out rooms.{rid}.members.{mno}.name(prevName:Str, updateName(mid, name)) = name +} + +channel UpdatePoint(rid:Str) { + in rooms.{rid}.battle(prevState, updatePoint(hasWon, mid)) = hasWon + for EachMember(mno:Int) { + in rooms.{rid}.members.{mno}.id(prevMid:Str, updatePoint(hasWon, mid)) = mid + out accounts.{mid}.point(prevPoint:Int, updatePoint(hasWon, mid)) = if(hasWon, prevPoint + 1, prevPoint) + } +} diff --git a/AlgebraicDataflowArchitectureModel/models/Twitter.model b/AlgebraicDataflowArchitectureModel/models/Twitter.model index 491d904..e5c46a8 100644 --- a/AlgebraicDataflowArchitectureModel/models/Twitter.model +++ b/AlgebraicDataflowArchitectureModel/models/Twitter.model @@ -1,16 +1,20 @@ -channel CIO1(myId:Str) { - out accounts(ac:List, signup(name:Str)) = cons(tuple(name, nil, nil), t1) +channel SignUp { + out accounts(acDB:Map, signup(id:Str, name:Str)) = insert(acDB, id, {"name": name, "tweets": nil, "followees": nil, "timeline": nil}) } -channel CIO2(id:Str) { - out accounts.{id}.tweets(t1:List, tweet(text:Str, time:Long)) = cons(tuple(time, text), t1) +channel Tweet(id:Str) { + out accounts.{id}.tweets(twList:List, tweet(text:Str, time:Long)) = append(twList, {"time": time, "text": text}) } -channel C(myId:Str; m:Json) { +channel AddFollowee(id:Str) { + out accounts.{id}.followees(fwList:List, addFollowee(flwId:Str)) = append(fwList, flwId) +} + +channel UpdateTimeline(myId:Str) { in accounts.{myId}.tweets(t1:List, m) = m.myTweets - sub C2(no:Int; flw:Json := m.followees.{no}) { - in accounts.{myId}.followees.{no}(id:Str, flw) = flw.id - in accounts.{flw.id}.tweets(t2:List, flw) = flw.tweets + for EachFollowee(no:Int) { + in accounts.{myId}.followees.{no}(id:Str, m) = m.flw.{no}.id + in accounts.{m.flw.{no}.id}.tweets(t2:List, m) = m.flw.{no}.tweets } - out accounts.{myId}.timeline(l:List, m) = merge(m.myTweets, m.followees) + out accounts.{myId}.timeline(l:List, m) = merge(m.myTweets, m.flw) } \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/src/algorithms/TypeInference.java b/AlgebraicDataflowArchitectureModel/src/algorithms/TypeInference.java index 45a82b9..f57b895 100644 --- a/AlgebraicDataflowArchitectureModel/src/algorithms/TypeInference.java +++ b/AlgebraicDataflowArchitectureModel/src/algorithms/TypeInference.java @@ -148,1058 +148,1106 @@ // 1. Collect type information from the architecture model. Collection channels = new HashSet<>(model.getInputChannels()); channels.addAll(model.getChannels()); - for (Channel c : channels) { - for (ChannelMember cm : c.getChannelMembers()) { - StateTransition st = cm.getStateTransition(); - ResourceHierarchy res = cm.getResource().getResourceHierarchy(); - - // 1.1 Group expressions by resources. - List identicalResources = resources.get(res); - if (identicalResources == null) { - identicalResources = new ArrayList<>(); - resources.put(res, identicalResources); - } - identicalResources.add(st.getCurStateExpression()); - expToResource.put(System.identityHashCode(st.getCurStateExpression()), identicalResources); - if (st.getNextStateExpression() != null) { - identicalResources.add(st.getNextStateExpression()); - expToResource.put(System.identityHashCode(st.getNextStateExpression()), identicalResources); - } - Map updatedExps = getUpdateSet(updateFromResource, identicalResources); - Type resType = res.getResourceStateType(); - Expression exp = st.getCurStateExpression(); - Type expType = getExpTypeIfUpdatable(resType, exp); - if (expType != null) { - res.setResourceStateType(expType); - for (Expression resExp : identicalResources) { - if (resExp != exp) { - if (resExp instanceof Variable && compareTypes(((Variable) resExp).getType(), expType)) { - ((Variable) resExp).setType(expType); - updatedExps.put(System.identityHashCode(resExp), resExp); - } else if (resExp instanceof Term && compareTypes(((Term) resExp).getType(), expType)) { - ((Term) resExp).setType(expType); - updatedExps.put(System.identityHashCode(resExp), resExp); - } + for (Channel ch : channels) { + // 1.1 Group expressions by resources. + IGroupExpressionsByResource groupExpressionsByResource = new IGroupExpressionsByResource() { + public void groupForChannel(Channel ch) { + for (ChannelMember cm : ch.getChannelMembers()) { + StateTransition st = cm.getStateTransition(); + ResourceHierarchy res = cm.getResource().getResourceHierarchy(); + List identicalResources = resources.get(res); + if (identicalResources == null) { + identicalResources = new ArrayList<>(); + resources.put(res, identicalResources); } - } - } else if (exp instanceof Variable) { - if (compareTypes(((Variable) exp).getType(), resType)) { - ((Variable) exp).setType(resType); - updatedExps.put(System.identityHashCode(exp), exp); - } - } else if (exp instanceof Term) { - if (compareTypes(((Term) exp).getType(), resType)) { - ((Term) exp).setType(resType); - updatedExps.put(System.identityHashCode(exp), exp); - } - } - resType = res.getResourceStateType(); - exp = st.getNextStateExpression(); - if (exp != null) { - expType = getExpTypeIfUpdatable(resType, exp); - if (expType != null) { - res.setResourceStateType(expType); - for (Expression resExp : identicalResources) { - if (resExp != exp) { - if (resExp instanceof Variable && compareTypes(((Variable) resExp).getType(), expType)) { - ((Variable) resExp).setType(expType); - updatedExps.put(System.identityHashCode(resExp), resExp); - } else if (resExp instanceof Term && compareTypes(((Term) resExp).getType(), expType)) { - ((Term) resExp).setType(expType); - updatedExps.put(System.identityHashCode(resExp), resExp); - } - } + identicalResources.add(st.getCurStateExpression()); + expToResource.put(System.identityHashCode(st.getCurStateExpression()), identicalResources); + if (st.getNextStateExpression() != null) { + identicalResources.add(st.getNextStateExpression()); + expToResource.put(System.identityHashCode(st.getNextStateExpression()), identicalResources); } - } else if (exp instanceof Variable) { - if (compareTypes(((Variable) exp).getType(), resType)) { - ((Variable) exp).setType(resType); - updatedExps.put(System.identityHashCode(exp), exp); - } - } else if (exp instanceof Term) { - if (compareTypes(((Term) exp).getType(), resType)) { - ((Term) exp).setType(resType); - updatedExps.put(System.identityHashCode(exp), exp); - } - } - } - - // 1.2 Group expressions by variable. - Map> locals = new HashMap<>(); - Map localTypes = new HashMap<>(); - List allVariables = new ArrayList<>(); - allVariables.addAll(st.getCurStateExpression().getVariables().values()); - allVariables.addAll(st.getMessageExpression().getVariables().values()); - if (st.getNextStateExpression() != null) { - allVariables.addAll(st.getNextStateExpression().getVariables().values()); - } - for (Selector s: c.getSelectors()) { // add channel selectors - if (s.getExpression() instanceof Variable) { - allVariables.add((Variable) s.getExpression()); - } - } - ResourcePath resPath = cm.getResource(); - for (Expression param: resPath.getPathParams()) { // add path parameters - if (param instanceof Variable) { - allVariables.add((Variable) param); - } else if (param instanceof Term) { - allVariables.addAll(((Term) param).getVariables().values()); - } - } - for (Variable var : allVariables) { - List sameVariable = locals.get(var.getName()); - if (sameVariable == null) { - sameVariable = new ArrayList<>(); - sameVariable.add(var); - expToVariable.put(System.identityHashCode(var), sameVariable); - locals.put(var.getName(), sameVariable); - localTypes.put(var.getName(), var.getType()); - } else { - sameVariable.add(var); - expToVariable.put(System.identityHashCode(var), sameVariable); - Type varType = localTypes.get(var.getName()); - Map updatedVars = getUpdateSet(updateFromVariable, sameVariable); - if (compareTypes(varType, var.getType())) { - localTypes.put(var.getName(), var.getType()); - for (Expression v : sameVariable) { - if (v != var) { - if (compareTypes(((Variable) v).getType(), var.getType())) { - ((Variable) v).setType(var.getType()); - updatedVars.put(System.identityHashCode(v), v); + Map updatedExps = getUpdateSet(updateFromResource, identicalResources); + Type resType = res.getResourceStateType(); + Expression exp = st.getCurStateExpression(); + Type expType = getExpTypeIfUpdatable(resType, exp); + if (expType != null) { + res.setResourceStateType(expType); + for (Expression resExp : identicalResources) { + if (resExp != exp) { + if (resExp instanceof Variable && compareTypes(((Variable) resExp).getType(), expType)) { + ((Variable) resExp).setType(expType); + updatedExps.put(System.identityHashCode(resExp), resExp); + } else if (resExp instanceof Term && compareTypes(((Term) resExp).getType(), expType)) { + ((Term) resExp).setType(expType); + updatedExps.put(System.identityHashCode(resExp), resExp); } } } - } else if (compareTypes(var.getType(), varType)) { - var.setType(varType); - updatedVars.put(System.identityHashCode(var), var); - } - } - } - for (String varName : locals.keySet()) { - variables.put(System.identityHashCode(locals.get(varName)), localTypes.get(varName)); - } - - // 1.3 Group expressions by message. - Expression message = st.getMessageExpression(); - if (message instanceof Variable) { - Type msgType = ((Variable) message).getType(); - Map, Type>> msgTypeMap = messages.get(c); - if (msgTypeMap == null) { - msgTypeMap = new HashMap<>(); - messages.put(c, msgTypeMap); - } - Map.Entry, Type> typeAndExps = msgTypeMap.get(0); - if (typeAndExps == null) { - List exps = new ArrayList<>(); - exps.add(message); - typeAndExps = new AbstractMap.SimpleEntry<>(exps, msgType); - msgTypeMap.put(0, typeAndExps); - expToMessage.put(System.identityHashCode(message), exps); - } else { - typeAndExps.getKey().add(message); - expToMessage.put(System.identityHashCode(message), typeAndExps.getKey()); - Map updateExps = getUpdateSet(updateFromMessage, typeAndExps.getKey()); - if (compareTypes(typeAndExps.getValue(), msgType)) { - typeAndExps.setValue(msgType); - for (Expression e : typeAndExps.getKey()) { - if (e != message) { - if (e instanceof Variable) { - ((Variable) e).setType(msgType); - updateExps.put(System.identityHashCode(e), e); - } - } + } else if (exp instanceof Variable) { + if (compareTypes(((Variable) exp).getType(), resType)) { + ((Variable) exp).setType(resType); + updatedExps.put(System.identityHashCode(exp), exp); } - } else if (compareTypes(msgType, typeAndExps.getValue())) { - ((Variable) message).setType(typeAndExps.getValue()); - updateExps.put(System.identityHashCode(message), message); + } else if (exp instanceof Term) { + if (compareTypes(((Term) exp).getType(), resType)) { + ((Term) exp).setType(resType); + updatedExps.put(System.identityHashCode(exp), exp); + } } - } - } else if (message instanceof Term) { - Map, Type>> msgTypeMap = messages.get(c); - if (msgTypeMap == null) { - msgTypeMap = new HashMap<>(); - messages.put(c, msgTypeMap); - } - for (int i = 0; i < ((Term) message).getArity(); i++) { - Expression arg = ((Term) message).getChild(i); - Type argType = null; - if (arg instanceof Variable) { - argType = ((Variable) arg).getType(); - } else if (arg instanceof Term) { - argType = ((Term) arg).getType(); - } else { - continue; - } - Map.Entry, Type> typeAndExps = msgTypeMap.get(i); - if (typeAndExps == null) { - List exps = new ArrayList<>(); - exps.add(arg); - typeAndExps = new AbstractMap.SimpleEntry<>(exps, argType); - msgTypeMap.put(i, typeAndExps); - expToMessage.put(System.identityHashCode(arg), exps); - } else { - typeAndExps.getKey().add(arg); - expToMessage.put(System.identityHashCode(arg), typeAndExps.getKey()); - Map updateExps = getUpdateSet(updateFromMessage, typeAndExps.getKey()); - if (compareTypes(typeAndExps.getValue(), argType)) { - typeAndExps.setValue(argType); - for (Expression e : typeAndExps.getKey()) { - if (e != arg) { - if (e instanceof Variable) { - ((Variable) e).setType(argType); - updateExps.put(System.identityHashCode(e), e); + resType = res.getResourceStateType(); + exp = st.getNextStateExpression(); + if (exp != null) { + expType = getExpTypeIfUpdatable(resType, exp); + if (expType != null) { + res.setResourceStateType(expType); + for (Expression resExp : identicalResources) { + if (resExp != exp) { + if (resExp instanceof Variable && compareTypes(((Variable) resExp).getType(), expType)) { + ((Variable) resExp).setType(expType); + updatedExps.put(System.identityHashCode(resExp), resExp); + } else if (resExp instanceof Term && compareTypes(((Term) resExp).getType(), expType)) { + ((Term) resExp).setType(expType); + updatedExps.put(System.identityHashCode(resExp), resExp); } } } - } else if (compareTypes(argType, typeAndExps.getValue())) { - if (arg instanceof Variable) { - ((Variable) arg).setType(typeAndExps.getValue()); - updateExps.put(System.identityHashCode(arg), arg); - } else if (arg instanceof Term) { - ((Term) arg).setType(typeAndExps.getValue()); - updateExps.put(System.identityHashCode(arg), arg); + } else if (exp instanceof Variable) { + if (compareTypes(((Variable) exp).getType(), resType)) { + ((Variable) exp).setType(resType); + updatedExps.put(System.identityHashCode(exp), exp); + } + } else if (exp instanceof Term) { + if (compareTypes(((Term) exp).getType(), resType)) { + ((Term) exp).setType(resType); + updatedExps.put(System.identityHashCode(exp), exp); } } } } - } - - // 1.4 Extract constraints on expressions in each term. - List terms = new ArrayList<>(); - if (st.getCurStateExpression() instanceof Term) { - Map subTerms = ((Term) st.getCurStateExpression()).getSubTerms(Term.class); - terms.addAll(subTerms.values()); - } - if (st.getMessageExpression() instanceof Term) { - Map subTerms = ((Term) st.getMessageExpression()).getSubTerms(Term.class); - terms.addAll(subTerms.values()); - } - if (st.getNextStateExpression() != null && st.getNextStateExpression() instanceof Term) { - Map subTerms = ((Term) st.getNextStateExpression()).getSubTerms(Term.class); - terms.addAll(subTerms.values()); - } - for (Term t : terms) { - Symbol symbol = t.getSymbol(); - if (symbol.equals(DataConstraintModel.cons) || symbol.equals(DataConstraintModel.set) || symbol.equals(DataConstraintModel.append)) { - // If the root symbol of the term is cons or set. - List consExps = new ArrayList<>(); - consExps.add(t); // list term - updateExpressionBelonging(expToConsOrSet, t, consExps); - if (symbol.equals(DataConstraintModel.cons)) { - // If the root symbol of the term is cons. - for (Expression e : t.getChildren()) { - consExps.add(e); - updateExpressionBelonging(expToConsOrSet, e, consExps); - } - } else if (symbol.equals(DataConstraintModel.append)) { - // If the root symbol of the term is append. - Expression e = t.getChildren().get(1); - consExps.add(e); // list element - updateExpressionBelonging(expToConsOrSet, e, consExps); - e = t.getChildren().get(0); - consExps.add(e); // list argument - updateExpressionBelonging(expToConsOrSet, e, consExps); - } else { - // If the root symbol of the term is set. - Expression e = t.getChildren().get(2); - consExps.add(e); // list element - updateExpressionBelonging(expToConsOrSet, e, consExps); - e = t.getChildren().get(0); - consExps.add(e); // list argument - updateExpressionBelonging(expToConsOrSet, e, consExps); - } - Type newType = getExpTypeIfUpdatable(t.getType(), consExps.get(2)); - if (newType != null) { - // If the type of the 2nd argument of cons (1st argument of set/append) is more concrete than the type of the term. - t.setType(newType); - Map updateCons = getUpdateSet(updateFromConsOrSet, consExps); - updateCons.put(System.identityHashCode(t), t); - } else { - Type arg2Type = null; - if (consExps.get(2) != null && consExps.get(2) instanceof Variable) { - arg2Type = ((Variable) consExps.get(2)).getType(); - if (compareTypes(arg2Type, t.getType())) { - // If the type of the term is more concrete than the type of the 2nd argument of cons (1st argument of set/append). - ((Variable) consExps.get(2)).setType(t.getType()); - Map updateCons = getUpdateSet(updateFromConsOrSet, consExps); - updateCons.put(System.identityHashCode(consExps.get(2)), consExps.get(2)); - } - } else if (consExps.get(2) != null && consExps.get(2) instanceof Term) { - arg2Type = ((Term) consExps.get(2)).getType(); - if (compareTypes(arg2Type, t.getType())) { - // If the type of the term is more concrete than the type of the 2nd argument of cons (1st argument of set/append). - ((Term) consExps.get(2)).setType(t.getType()); - Map updateCons = getUpdateSet(updateFromConsOrSet, consExps); - updateCons.put(System.identityHashCode(consExps.get(2)), consExps.get(2)); - } - } - } - Type newCompType = getExpTypeIfUpdatable(listComponentTypes.get(t.getType()), consExps.get(1)); - if (newCompType != null) { - // If the type of the 1st argument of cons (3rd argument of set) is more concrete than the type of list component. - Type newListType = listTypes.get(newCompType); - if (newListType == null) { - // Create new list type. - newListType = createNewListType(newCompType, DataConstraintModel.typeList); - } - t.setType(newListType); - Map updateCons = getUpdateSet(updateFromConsOrSet, consExps); - updateCons.put(System.identityHashCode(t), t); - if (consExps.get(2) != null && consExps.get(2) instanceof Variable) { - ((Variable) consExps.get(2)).setType(newListType); - updateCons.put(System.identityHashCode(consExps.get(2)), consExps.get(2)); - } else if (consExps.get(2) != null && consExps.get(2) instanceof Term) { - ((Term) consExps.get(2)).setType(newListType); - updateCons.put(System.identityHashCode(consExps.get(2)), consExps.get(2)); - } - } - consOrSet.put(System.identityHashCode(consExps), t.getType()); - } else if (symbol.equals(DataConstraintModel.head) || symbol.equals(DataConstraintModel.get)) { - // If the root symbol of the term is head or get. - List consExps = new ArrayList<>(); - Expression e = t.getChildren().get(0); - consExps.add(e); // list argument - updateExpressionBelonging(expToConsOrSet, e, consExps); - consExps.add(t); // list's component - updateExpressionBelonging(expToConsOrSet, t, consExps); - consExps.add(null); - Type listType = listTypes.get(t.getType()); - if (listType == null && t.getType() != null) { - // Create a new list type. - listType = createNewListType(t.getType(), DataConstraintModel.typeList); - } - Type newListType = getExpTypeIfUpdatable(listType, consExps.get(0)); - if (newListType != null) { - // If the type of the component of the 1st argument is more concrete than the type of the term. - Type newCompType = listComponentTypes.get(newListType); - if (newCompType != null) { - t.setType(newCompType); - Map updateCons = getUpdateSet(updateFromConsOrSet, consExps); - updateCons.put(System.identityHashCode(t), t); - } - consOrSet.put(System.identityHashCode(consExps), newListType); - } else { - // If the type of the term is more concrete than the type of the component of the 1st argument. - if (consExps.get(0) != null && consExps.get(0) instanceof Variable) { - ((Variable) consExps.get(0)).setType(listType); - Map updateCons = getUpdateSet(updateFromConsOrSet, consExps); - updateCons.put(System.identityHashCode(consExps.get(0)), consExps.get(0)); - } else if (consExps.get(0) != null && consExps.get(0) instanceof Term) { - ((Term) consExps.get(0)).setType(listType); - Map updateCons = getUpdateSet(updateFromConsOrSet, consExps); - updateCons.put(System.identityHashCode(consExps.get(0)), consExps.get(0)); - } - consOrSet.put(System.identityHashCode(consExps), listType); - } - } else if (symbol.equals(DataConstraintModel.tail)) { - // If the root symbol of the term is tail. - List consExps = new ArrayList<>(); - consExps.add(t); // list term - updateExpressionBelonging(expToConsOrSet, t, consExps); - consExps.add(null); // list's component - Expression e = t.getChildren().get(0); - consExps.add(e); // list argument - updateExpressionBelonging(expToConsOrSet, e, consExps); - Type newType = getExpTypeIfUpdatable(t.getType(), consExps.get(2)); - if (newType != null) { - // If the type of the argument is more concrete than the type of the term. - t.setType(newType); - Map updateCons = getUpdateSet(updateFromConsOrSet, consExps); - updateCons.put(System.identityHashCode(t), t); - } else { - Type argType = null; - if (consExps.get(2) != null && consExps.get(2) instanceof Variable) { - argType = ((Variable) consExps.get(2)).getType(); - if (compareTypes(argType, t.getType())) { - // If the type of the term is more concrete than the type of the argument. - ((Variable) consExps.get(2)).setType(t.getType()); - Map updateCons = getUpdateSet(updateFromConsOrSet, consExps); - updateCons.put(System.identityHashCode(consExps.get(2)), consExps.get(2)); - } - } else if (consExps.get(2) != null && consExps.get(2) instanceof Term) { - argType = ((Term) consExps.get(2)).getType(); - if (compareTypes(argType, t.getType())) { - // If the type of the term is more concrete than the type of the argument. - ((Term) consExps.get(2)).setType(t.getType()); - Map updateCons = getUpdateSet(updateFromConsOrSet, consExps); - updateCons.put(System.identityHashCode(consExps.get(2)), consExps.get(2)); - } - } - } - consOrSet.put(System.identityHashCode(consExps), t.getType()); - } else if (symbol.equals(DataConstraintModel.tuple)) { - // If the root symbol of the term is tuple. - List tupleExps = new ArrayList<>(); - List newArgTypesList = new ArrayList<>(); - tupleExps.add(t); // tuple term - updateExpressionBelonging(expToTuple, t, tupleExps); - for (Expression e : t.getChildren()) { - tupleExps.add(e); // tuple's component - updateExpressionBelonging(expToTuple, e, tupleExps); - if (e instanceof Variable) { - newArgTypesList.add(((Variable) e).getType()); - } else if (e instanceof Term) { - newArgTypesList.add(((Term) e).getType()); - } else { - newArgTypesList.add(null); - } - } - if (t.getType() == DataConstraintModel.typeTuple) { - Type newTupleType = tupleTypes.get(newArgTypesList); - if (newTupleType == null) { - // Create new tuple type; - newTupleType = createNewTupleType(newArgTypesList, DataConstraintModel.typeTuple); - } - // Update the type of the tuple term and record the updated expression. - t.setType(newTupleType); - Map updateExps = getUpdateSet(updateFromTuple, tupleExps); - updateExps.put(System.identityHashCode(t), t); - } - tuple.put(System.identityHashCode(tupleExps), t.getType()); - } else if (symbol.equals(DataConstraintModel.pair)) { - // If the root symbol of the term is pair. - List pairExps = new ArrayList<>(); - pairExps.add(t); // pair - updateExpressionBelonging(expToPair, t, pairExps); - if (t.getType() == DataConstraintModel.typePair) { - for (Expression e : t.getChildren()) { - pairExps.add(e); // left/right - updateExpressionBelonging(expToPair, e, pairExps); - Type newArgType = null; - if (e instanceof Variable) { - newArgType = (((Variable) e).getType()); - - } else if (e instanceof Term) { - newArgType = (((Term) e).getType()); - } - - if (newArgType != null) { - Type newPairType = pairTypes.get(newArgType); - if (newPairType != null) { - t.setType(newPairType); - Map updateExps = getUpdateSet(updateFromPair, pairExps); - updateExps.put(System.identityHashCode(t), t); - } - } - } - pair.put(System.identityHashCode(pairExps), t.getType()); - - } - } else if (symbol.equals(DataConstraintModel.fst)) { - // If the root symbol of the term is fst. - List tupleExps = new ArrayList<>(); - Expression arg = t.getChildren().get(0); - tupleExps.add(arg); // tuple argument - updateExpressionBelonging(expToTuple, arg, tupleExps); - tupleExps.add(t); // first component - updateExpressionBelonging(expToTuple, t, tupleExps); - tupleExps.add(null); // second component - Type argType = null; - if (arg instanceof Variable) { - argType = ((Variable) arg).getType(); - } else if (arg instanceof Term) { - argType = ((Term) arg).getType(); - } - Type newTupleType = DataConstraintModel.typeTuple; - if (argType == DataConstraintModel.typeTuple && t.getType() != null) { - List newCompTypeList = new ArrayList<>(); - newCompTypeList.add(t.getType()); - newCompTypeList.add(null); - newTupleType = tupleTypes.get(newCompTypeList); - if (newTupleType == null) { - // Create new tuple type; - newTupleType = createNewTupleType(newCompTypeList, DataConstraintModel.typeTuple); - } - } - if (argType != newTupleType && newTupleType != null) { - // Update the type of the tuple argument and record the updated expression. - if (arg instanceof Variable) { - ((Variable) arg).setType(newTupleType); - argType = newTupleType; - } else if (arg instanceof Term) { - ((Term) arg).setType(newTupleType); - argType = newTupleType; - } - Map updateExps = getUpdateSet(updateFromTuple, tupleExps); - updateExps.put(System.identityHashCode(arg), arg); - } - tuple.put(System.identityHashCode(tupleExps), argType); - } else if (symbol.equals(DataConstraintModel.snd)) { - // If the root symbol of the term is snd. - List tupleExps = new ArrayList<>(); - Expression arg = t.getChildren().get(0); - tupleExps.add(arg); // tuple argument - updateExpressionBelonging(expToTuple, arg, tupleExps); - tupleExps.add(null); // first component - tupleExps.add(t); // second component - updateExpressionBelonging(expToTuple, t, tupleExps); - Type argType = null; - if (arg instanceof Variable) { - argType = ((Variable) arg).getType(); - } else if (arg instanceof Term) { - argType = ((Term) arg).getType(); - } - Type newTupleType = DataConstraintModel.typeTuple; - if (argType == DataConstraintModel.typeTuple && t.getType() != null) { - List newCompTypeList = new ArrayList<>(); - newCompTypeList.add(null); - if (DataConstraintModel.typeTuple.isAncestorOf(t.getType())) { - List sndTypes = tupleComponentTypes.get(t.getType()); - if (sndTypes != null) { - for (Type t2: sndTypes) { - newCompTypeList.add(t2); - } - } else { - newCompTypeList.add(t.getType()); - } - } else { - newCompTypeList.add(t.getType()); - } - newTupleType = tupleTypes.get(newCompTypeList); - if (newTupleType == null) { - // Create new tuple type; - newTupleType = createNewTupleType(newCompTypeList, DataConstraintModel.typeTuple); - } - } - if (argType != newTupleType && newTupleType != null) { - // Update the type of the tuple argument and record the updated expression. - if (arg instanceof Variable) { - ((Variable) arg).setType(newTupleType); - argType = newTupleType; - } else if (arg instanceof Term) { - ((Term) arg).setType(newTupleType); - argType = newTupleType; - } - Map updateExps = getUpdateSet(updateFromTuple, tupleExps); - updateExps.put(System.identityHashCode(arg), arg); - } - tuple.put(System.identityHashCode(tupleExps), argType); - } else if (symbol.equals(DataConstraintModel.left)) { - // If the root symbol of the term is left. - List pairExps = new ArrayList<>(); - Expression arg = t.getChildren().get(0); - pairExps.add(arg); // pair - updateExpressionBelonging(expToPair, arg, pairExps); - pairExps.add(t); // left - updateExpressionBelonging(expToPair, t, pairExps); - pairExps.add(null); // right - Type argType = null; - if (arg instanceof Variable) { - argType = ((Variable) arg).getType(); - } else if (arg instanceof Term) { - argType = ((Term) arg).getType(); - } - Type newPairType = DataConstraintModel.typePair; - if (argType == DataConstraintModel.typePair && t.getType() != null) { - List newCompTypeList = new ArrayList<>(); - newCompTypeList.add(t.getType()); - newCompTypeList.add(null); - newPairType = pairTypes.get(newCompTypeList); - if (newPairType == null) { - // Create new tuple type; - newPairType = createNewTupleType(newCompTypeList, DataConstraintModel.typePair); - } - } - if (argType != newPairType && newPairType != null) { - if (arg instanceof Variable) { - ((Variable) arg).setType(newPairType); - argType = newPairType; - } else if (arg instanceof Term) { - ((Term) arg).setType(newPairType); - argType = newPairType; - } - Map updateExps = getUpdateSet(updateFromPair, pairExps); - updateExps.put(System.identityHashCode(arg), arg); - } - pair.put(System.identityHashCode(pairExps), argType); - } else if (symbol.equals(DataConstraintModel.right)) { - // If the root symbol of the term is right. - List pairExps = new ArrayList<>(); - Expression arg = t.getChildren().get(0); - pairExps.add(arg); // pair - updateExpressionBelonging(expToPair, arg, pairExps); - pairExps.add(null); // left - pairExps.add(t); // right - updateExpressionBelonging(expToPair, t, pairExps); - Type argType = null; - if (arg instanceof Variable) { - argType = ((Variable) arg).getType(); - } else if (arg instanceof Term) { - argType = ((Term) arg).getType(); - } - Type newPairType = DataConstraintModel.typePair; - if (argType == DataConstraintModel.typePair && t.getType() != null) { - List newCompTypeList = new ArrayList<>(); - newCompTypeList.add(null); - newCompTypeList.add(t.getType()); - newPairType = pairTypes.get(newCompTypeList); - if (newPairType == null) { - // Create new tuple type; - newPairType = createNewTupleType(newCompTypeList, DataConstraintModel.typePair); - } - } - if (argType != newPairType && newPairType != null) { - if (arg instanceof Variable) { - ((Variable) arg).setType(newPairType); - argType = newPairType; - } else if (arg instanceof Term) { - ((Term) arg).setType(newPairType); - argType = newPairType; - } - Map updateExps = getUpdateSet(updateFromPair, pairExps); - updateExps.put(System.identityHashCode(arg), arg); - } - pair.put(System.identityHashCode(pairExps), argType); - } else if (symbol.equals(DataConstraintModel.lookup)) { - // If the root symbol of the term is lookup. - List mapExps = new ArrayList<>(); - Expression arg1 = t.getChildren().get(0); // map - mapExps.add(arg1); - updateExpressionBelonging(expToMap, arg1, mapExps); - Expression arg2 = t.getChildren().get(1); // key - mapExps.add(arg2); - updateExpressionBelonging(expToMap, arg2, mapExps); - mapExps.add(t); // value - updateExpressionBelonging(expToMap, t, mapExps); - Type arg1Type = null; - if (arg1 instanceof Variable) { - arg1Type = ((Variable) arg1).getType(); - } else if (arg1 instanceof Term) { - arg1Type = ((Term) arg1).getType(); - } - List newCompTypeList = new ArrayList<>(); - if (arg2 instanceof Variable) { - newCompTypeList.add(((Variable) arg2).getType()); - } else if (arg2 instanceof Term) { - newCompTypeList.add(((Term) arg2).getType()); - } else { - newCompTypeList.add(null); - } - newCompTypeList.add(t.getType()); - if (arg1Type == DataConstraintModel.typeMap || arg1Type == null) { - Type newMapType = mapTypes.get(newCompTypeList); - if (newMapType == null) { - // Create new tuple type; - newMapType = createNewMapType(newCompTypeList, DataConstraintModel.typeMap); - } - // Update the type of the map argument and record the updated expression. - if (arg1 instanceof Variable) { - ((Variable) arg1).setType(newMapType); - arg1Type = newMapType; - } else if (arg1 instanceof Term) { - ((Term) arg1).setType(newMapType); - arg1Type = newMapType; - } - Map updateExps = getUpdateSet(updateFromMap, mapExps); - updateExps.put(System.identityHashCode(arg1), arg1); - } - map.put(System.identityHashCode(mapExps), arg1Type); - } else if (symbol.equals(DataConstraintModel.insert)) { - // If the root symbol of the term is insert. - List mapExps = new ArrayList<>(); - mapExps.add(t); // map - updateExpressionBelonging(expToMap, t, mapExps); - Expression arg1 = t.getChildren().get(1); // key - mapExps.add(arg1); - updateExpressionBelonging(expToMap, arg1, mapExps); - Expression arg2 = t.getChildren().get(2); // value - mapExps.add(arg2); - updateExpressionBelonging(expToMap, arg2, mapExps); - Expression arg0 = t.getChildren().get(0); // map - mapExps.add(arg0); - updateExpressionBelonging(expToMap, arg0, mapExps); - Type termType = t.getType(); - List newCompTypeList = new ArrayList<>(); - if (arg1 instanceof Variable) { - newCompTypeList.add(((Variable) arg1).getType()); - } else if (arg1 instanceof Term) { - newCompTypeList.add(((Term) arg1).getType()); - } else { - newCompTypeList.add(null); - } - if (arg2 instanceof Variable) { - newCompTypeList.add(((Variable) arg2).getType()); - } else if (arg2 instanceof Term) { - newCompTypeList.add(((Term) arg2).getType()); - } else { - newCompTypeList.add(null); - } - Type newTermType = getExpTypeIfUpdatable(termType, mapExps.get(3)); - if (newTermType != null) { - // If the type of the 1st argument of insert is more concrete than the type of the term. - t.setType(newTermType); - termType = newTermType; - Map updateExps = getUpdateSet(updateFromMap, mapExps); - updateExps.put(System.identityHashCode(t), t); - } else { - Type arg3Type = null; - if (mapExps.get(3) != null && mapExps.get(3) instanceof Variable) { - arg3Type = ((Variable) mapExps.get(3)).getType(); - if (compareTypes(arg3Type, t.getType())) { - // If the type of the term is more concrete than the type of the 1st argument of insert. - ((Variable) mapExps.get(3)).setType(t.getType()); - Map updateExps = getUpdateSet(updateFromMap, mapExps); - updateExps.put(System.identityHashCode(mapExps.get(3)), mapExps.get(3)); - } - } else if (mapExps.get(3) != null && mapExps.get(3) instanceof Term) { - arg3Type = ((Term) mapExps.get(3)).getType(); - if (compareTypes(arg3Type, t.getType())) { - // If the type of the term is more concrete than the type of the 1st argument of insert. - ((Term) mapExps.get(3)).setType(t.getType()); - Map updateExps = getUpdateSet(updateFromMap, mapExps); - updateExps.put(System.identityHashCode(mapExps.get(3)), mapExps.get(3)); - } - } - } - if (termType == DataConstraintModel.typeMap || termType == null) { - Type newMapType = mapTypes.get(newCompTypeList); - if (newMapType == null) { - // Create new tuple type; - newMapType = createNewMapType(newCompTypeList, DataConstraintModel.typeMap); - } - // Update the type of the map term and record the updated expression. - t.setType(newMapType); - Map updateExps = getUpdateSet(updateFromMap, mapExps); - updateExps.put(System.identityHashCode(t), t); - if (mapExps.get(3) != null && mapExps.get(3) instanceof Variable) { - ((Variable) mapExps.get(3)).setType(newMapType); - updateExps.put(System.identityHashCode(mapExps.get(3)), mapExps.get(3)); - } else if (mapExps.get(3) != null && mapExps.get(3) instanceof Term) { - ((Term) mapExps.get(3)).setType(newMapType); - updateExps.put(System.identityHashCode(mapExps.get(3)), mapExps.get(3)); - } - termType = newMapType; - } - map.put(System.identityHashCode(mapExps), termType); - } else if (symbol.equals(DataConstraintModel.addMember)) { - // If the root symbol of the term is addMember (addMember(json, key, value)). - List dotExps = new ArrayList<>(); - Expression jsonArg = t.getChildren().get(0); - Expression keyArg = t.getChildren().get(1); - Expression valueArg = t.getChildren().get(2); - dotExps.add(t); // json - updateExpressionBelonging(expToJson, t, dotExps); - dotExps.add(keyArg); // key - updateExpressionBelonging(expToJson, keyArg, dotExps); - dotExps.add(valueArg); // value - updateExpressionBelonging(expToJson, valueArg, dotExps); - dotExps.add(jsonArg); // json - updateExpressionBelonging(expToJson, jsonArg, dotExps); - Type jsonType = t.getType(); - Type valueType = null; - if (valueArg instanceof Variable) { - valueType = ((Variable) valueArg).getType(); - } else if (valueArg instanceof Term) { - valueType = ((Term) valueArg).getType(); - } - String keyName = null; - if (keyArg instanceof Constant) { - keyName = ((Constant) keyArg).getSymbol().getName(); - } - Type jsonArgType = null; - if (jsonArg instanceof Variable) { - jsonArgType = ((Variable) jsonArg).getType(); - } else if (jsonArg instanceof Term) { - jsonArgType = ((Term) jsonArg).getType(); - } - Type newJsonType = DataConstraintModel.typeJson; - if (jsonType == DataConstraintModel.typeJson && jsonArgType != null && keyName != null) { - Map newMemberTypes = new HashMap<>(((JsonType) jsonArgType).getMemberTypes()); - newMemberTypes.put(keyName, valueType); - newJsonType = jsonTypes.get(newMemberTypes); - if (newJsonType == null) { - // Create new json type; - newJsonType = createNewJsonType(newMemberTypes, DataConstraintModel.typeJson); - } - } - if (jsonType != newJsonType && newJsonType != null && !newJsonType.isAncestorOf(jsonType)) { - // Update the type of the json term and record the updated expression. - t.setType(newJsonType); - jsonType = newJsonType; - Map updateExps = getUpdateSet(updateFromJson, dotExps); - updateExps.put(System.identityHashCode(t), t); - } - json.put(System.identityHashCode(dotExps), jsonType); - } else if (symbol.equals(DataConstraintModel.dot)) { - // If the root symbol of the term is dot (json.property). - List dotExps = new ArrayList<>(); - Expression jsonArg = t.getChildren().get(0); - Expression keyArg = t.getChildren().get(1); - dotExps.add(jsonArg); // json - updateExpressionBelonging(expToJson, jsonArg, dotExps); - dotExps.add(keyArg); // key - updateExpressionBelonging(expToJson, keyArg, dotExps); - dotExps.add(t); // value - updateExpressionBelonging(expToJson, t, dotExps); - dotExps.add(null); // json - Type jsonType = null; - if (jsonArg instanceof Variable) { - jsonType = ((Variable) jsonArg).getType(); - } else if (jsonArg instanceof Term) { - jsonType = ((Term) jsonArg).getType(); - } - String keyName = null; - if (keyArg instanceof Constant) { - keyName = ((Constant) keyArg).getSymbol().getName(); - } - Type newJsonType = DataConstraintModel.typeJson; - if (jsonType == DataConstraintModel.typeJson && t.getType() != null && keyName != null) { - Map newMemberTypes = new HashMap<>(); - newMemberTypes.put(keyName, t.getType()); - newJsonType = jsonTypes.get(newMemberTypes); - if (newJsonType == null) { - // Create new json type; - newJsonType = createNewJsonType(newMemberTypes, DataConstraintModel.typeJson); - } - } - if (jsonType != newJsonType && newJsonType != null && !newJsonType.isAncestorOf(jsonType)) { - // Update the type of the json argument and record the updated expression. - if (jsonArg instanceof Variable) { - ((Variable) jsonArg).setType(newJsonType); - jsonType = newJsonType; - } else if (jsonArg instanceof Term) { - ((Term) jsonArg).setType(newJsonType); - jsonType = newJsonType; - } - Map updateExps = getUpdateSet(updateFromJson, dotExps); - updateExps.put(System.identityHashCode(jsonArg), jsonArg); - } - json.put(System.identityHashCode(dotExps), jsonType); - } else if (symbol.equals(DataConstraintModel.dotParam)) { - // If the root symbol of the term is dot (json.{param}). - List dotExps = new ArrayList<>(); - Expression jsonArg = t.getChildren().get(0); - Expression keyArg = t.getChildren().get(1); - dotExps.add(jsonArg); // json (list/map) - updateExpressionBelonging(expToJson, jsonArg, dotExps); - dotExps.add(null); // key - dotExps.add(t); // value - updateExpressionBelonging(expToJson, t, dotExps); - dotExps.add(null); // json - Type jsonType = null; - if (jsonArg instanceof Variable) { - jsonType = ((Variable) jsonArg).getType(); - } else if (jsonArg instanceof Term) { - jsonType = ((Term) jsonArg).getType(); - } - Type keyType = null; - if (keyArg instanceof Variable) { - keyType = ((Variable) keyArg).getType(); - } else if (keyArg instanceof Term) { - keyType = ((Term) keyArg).getType(); - } - Type newJsonType = null; - if (keyType == DataConstraintModel.typeInt) { - newJsonType = DataConstraintModel.typeList; - } else if (keyType == DataConstraintModel.typeString) { - newJsonType = DataConstraintModel.typeMap; - } - if (t.getType() != null) { - if ((jsonType == DataConstraintModel.typeList)) { - newJsonType = listTypes.get(t.getType()); - if (newJsonType == null) { - // Create new list type; - newJsonType = createNewListType(t.getType(), DataConstraintModel.typeList); - } - } else if (jsonType == DataConstraintModel.typeMap) { - List keyValueTypes = Arrays.asList(new Type[] {DataConstraintModel.typeString, t.getType()}); - newJsonType = mapTypes.get(keyValueTypes); - if (newJsonType == null) { - // Create new map type; - newJsonType = createNewMapType(keyValueTypes, DataConstraintModel.typeMap); - } - } - } - if (jsonType != newJsonType && newJsonType != null && !newJsonType.isAncestorOf(jsonType)) { - // Update the type of the json argument and record the updated expression. - if (jsonArg instanceof Variable) { - ((Variable) jsonArg).setType(newJsonType); - jsonType = newJsonType; - } else if (jsonArg instanceof Term) { - ((Term) jsonArg).setType(newJsonType); - jsonType = newJsonType; - } - Map updateExps = getUpdateSet(updateFromJson, dotExps); - updateExps.put(System.identityHashCode(jsonArg), jsonArg); - } - json.put(System.identityHashCode(dotExps), jsonType); - } else if (symbol.equals(DataConstraintModel.cond)) { - // If the root symbol of the term is if function. - Expression c1 = t.getChild(1); - Expression c2 = t.getChild(2); - List condTerms = new ArrayList<>(); - condTerms.add(t); - condTerms.add(c1); - condTerms.add(c2); - expToVariable.put(System.identityHashCode(t), condTerms); - expToVariable.put(System.identityHashCode(c1), condTerms); - expToVariable.put(System.identityHashCode(c2), condTerms); - Type condType = t.getType(); - Map updatedVars = getUpdateSet(updateFromVariable, condTerms); - Type child1Type = getExpTypeIfUpdatable(condType, c1); - if (child1Type != null) { - condType = child1Type; - t.setType(child1Type); - updatedVars.put(System.identityHashCode(t), t); - } else { - if (c1 instanceof Variable && compareTypes(((Variable) c1).getType(), condType)) { - ((Variable) c1).setType(condType); - updatedVars.put(System.identityHashCode(c1), c1); - } else if (c1 instanceof Term && compareTypes(((Term) c1).getType(), condType)) { - ((Term) c1).setType(condType); - updatedVars.put(System.identityHashCode(c1), c1); - } - } - Type child2Type = getExpTypeIfUpdatable(condType, c2); - if (child2Type != null) { - condType = child2Type; - t.setType(child2Type); - updatedVars.put(System.identityHashCode(t), t); - if (c1 instanceof Variable) { - ((Variable) c1).setType(child2Type); - updatedVars.put(System.identityHashCode(c1), c1); - } else if (c1 instanceof Term) { - ((Term) c1).setType(child2Type); - updatedVars.put(System.identityHashCode(c1), c1); - } - } else { - if (c2 instanceof Variable && compareTypes(((Variable) c2).getType(), condType)) { - ((Variable) c2).setType(condType); - updatedVars.put(System.identityHashCode(c2), c2); - } else if (c2 instanceof Term && compareTypes(((Term) c2).getType(), condType)) { - ((Term) c2).setType(condType); - updatedVars.put(System.identityHashCode(c2), c2); - } - } - variables.put(System.identityHashCode(condTerms), condType); - } else if (symbol.equals(DataConstraintModel.add) || symbol.equals(DataConstraintModel.sub) - || symbol.equals(DataConstraintModel.mul) || symbol.equals(DataConstraintModel.div)) { - // If the root symbol of the term is arithmetic operators. - Expression c1 = t.getChild(0); - Expression c2 = t.getChild(1); - List operands = new ArrayList<>(); - operands.add(t); - operands.add(c1); - operands.add(c2); - expToVariable.put(System.identityHashCode(t), operands); - expToVariable.put(System.identityHashCode(c1), operands); - expToVariable.put(System.identityHashCode(c2), operands); - Type opType = t.getType(); - Map updatedVars = getUpdateSet(updateFromVariable, operands); - Type child1Type = getExpTypeIfUpdatable(opType, c1); - if (child1Type != null) { - opType = child1Type; - t.setType(child1Type); - updatedVars.put(System.identityHashCode(t), t); - } else { - if (c1 instanceof Variable && compareTypes(((Variable) c1).getType(), opType)) { - ((Variable) c1).setType(opType); - updatedVars.put(System.identityHashCode(c1), c1); - } else if (c1 instanceof Term && compareTypes(((Term) c1).getType(), opType)) { - ((Term) c1).setType(opType); - updatedVars.put(System.identityHashCode(c1), c1); - } - } - Type child2Type = getExpTypeIfUpdatable(opType, c2); - if (child2Type != null) { - opType = child2Type; - t.setType(child2Type); - updatedVars.put(System.identityHashCode(t), t); - if (c1 instanceof Variable) { - ((Variable) c1).setType(child2Type); - updatedVars.put(System.identityHashCode(c1), c1); - } else if (c1 instanceof Term) { - ((Term) c1).setType(child2Type); - updatedVars.put(System.identityHashCode(c1), c1); - } - } else { - if (c2 instanceof Variable && compareTypes(((Variable) c2).getType(), opType)) { - ((Variable) c2).setType(opType); - updatedVars.put(System.identityHashCode(c2), c2); - } else if (c2 instanceof Term && compareTypes(((Term) c2).getType(), opType)) { - ((Term) c2).setType(opType); - updatedVars.put(System.identityHashCode(c2), c2); - } - } - variables.put(System.identityHashCode(operands), opType); - } else if (symbol.getSignature() != null - && symbol.getSignature()[0] == DataConstraintModel.typeList) { - // If the root symbol of the term is the list type (except for the cons - // function). - List consExps = new ArrayList<>(); - consExps.add(t); - expToVariable.put(System.identityHashCode(t), consExps); - Type condType = t.getType(); - Map updatedVars = getUpdateSet(updateFromVariable, consExps); - for (int i = 1; i < symbol.getSignature().length; i++) { - Type tc = symbol.getSignature()[i]; - if (tc == DataConstraintModel.typeList) { - Expression e = t.getChildren().get(i - 1); - Type newType = getExpTypeIfUpdatable(condType, e); - if (newType != null) { - condType = newType; - for (Expression e2 : consExps) { - if (e2 instanceof Variable) { - ((Variable) e2).setType(newType); - updatedVars.put(System.identityHashCode(e2), e2); - } else if (e2 instanceof Term) { - ((Term) e2).setType(newType); - updatedVars.put(System.identityHashCode(e2), e2); - } - } - } else { - if (e instanceof Variable && compareTypes(((Variable) e).getType(), condType)) { - ((Variable) e).setType(condType); - updatedVars.put(System.identityHashCode(e), e); - } else if (e instanceof Term && compareTypes(((Term) e).getType(), condType)) { - ((Term) e).setType(condType); - updatedVars.put(System.identityHashCode(e), e); - } - } - consExps.add(e); - expToVariable.put(System.identityHashCode(e), consExps); - } - } - variables.put(System.identityHashCode(consExps), condType); + for (Channel childCh: ch.getChildren()) { + groupForChannel(childCh); } } + }; + groupExpressionsByResource.groupForChannel(ch); - // 1.5 Extract constraints on path parameters and resources. - ResourcePath rPath = cm.getResource(); - while (rPath != null) { - Expression param = rPath.getLastParam(); - if (param != null) { - ResourceHierarchy parent = rPath.getResourceHierarchy().getParent(); - if (parent != null) { - List pathParams = resourcePathParams.get(parent); - if (pathParams == null) { - pathParams = new ArrayList<>(); - resourcePathParams.put(parent, pathParams); + // 1.2 Group expressions by variable. + IGroupExpressionsByVariable groupExpressionsByVariable = new IGroupExpressionsByVariable() { + public void groupForChannel(Channel ch) { + for (ChannelMember cm : ch.getChannelMembers()) { + StateTransition st = cm.getStateTransition(); + Map> locals = new HashMap<>(); + Map localTypes = new HashMap<>(); + List allVariables = new ArrayList<>(); + allVariables.addAll(st.getCurStateExpression().getVariables().values()); + allVariables.addAll(st.getMessageExpression().getVariables().values()); + if (st.getNextStateExpression() != null) { + allVariables.addAll(st.getNextStateExpression().getVariables().values()); + } + for (Selector s: ch.getAllSelectors()) { // add channel selectors + if (s.getExpression() instanceof Variable) { + allVariables.add((Variable) s.getExpression()); } - pathParams.add(param); - expToPathParams.put(System.identityHashCode(param), pathParams); - Type parentType = parent.getResourceStateType(); - Type paramType = null; + } + ResourcePath resPath = cm.getResource(); + for (Expression param: resPath.getPathParams()) { // add path parameters if (param instanceof Variable) { - paramType = ((Variable) param).getType(); + allVariables.add((Variable) param); } else if (param instanceof Term) { - paramType = ((Term) param).getType(); + allVariables.addAll(((Term) param).getVariables().values()); } - if (paramType != null && parentType == null) { - if (paramType.equals(DataConstraintModel.typeString)) { - parentType = DataConstraintModel.typeMap; - } else if (paramType.equals(DataConstraintModel.typeInt)) { - parentType = DataConstraintModel.typeList; + } + for (Variable var : allVariables) { + List sameVariable = locals.get(var.getName()); + if (sameVariable == null) { + sameVariable = new ArrayList<>(); + sameVariable.add(var); + expToVariable.put(System.identityHashCode(var), sameVariable); + locals.put(var.getName(), sameVariable); + localTypes.put(var.getName(), var.getType()); + } else { + sameVariable.add(var); + expToVariable.put(System.identityHashCode(var), sameVariable); + Type varType = localTypes.get(var.getName()); + Map updatedVars = getUpdateSet(updateFromVariable, sameVariable); + if (compareTypes(varType, var.getType())) { + localTypes.put(var.getName(), var.getType()); + for (Expression v : sameVariable) { + if (v != var) { + if (compareTypes(((Variable) v).getType(), var.getType())) { + ((Variable) v).setType(var.getType()); + updatedVars.put(System.identityHashCode(v), v); + } + } + } + } else if (compareTypes(var.getType(), varType)) { + var.setType(varType); + updatedVars.put(System.identityHashCode(var), var); } - if (parentType != null) { - parent.setResourceStateType(parentType); - updateFromResourceOwnership.add(parent); + } + } + for (String varName : locals.keySet()) { + variables.put(System.identityHashCode(locals.get(varName)), localTypes.get(varName)); + } + } + for (Channel childCh: ch.getChildren()) { + groupForChannel(childCh); + } + } + }; + groupExpressionsByVariable.groupForChannel(ch); + + // 1.3 Group expressions by message. + IGroupExpressionsByMessage groupExpressionsByMessage = new IGroupExpressionsByMessage() { + public void groupForChannel(Channel rootCh, Channel ch) { + for (ChannelMember cm : ch.getChannelMembers()) { + Expression message = cm.getStateTransition().getMessageExpression(); + if (message instanceof Variable) { + Type msgType = ((Variable) message).getType(); + Map, Type>> msgTypeMap = messages.get(rootCh); + if (msgTypeMap == null) { + msgTypeMap = new HashMap<>(); + messages.put(rootCh, msgTypeMap); + } + Map.Entry, Type> typeAndExps = msgTypeMap.get(0); + if (typeAndExps == null) { + List exps = new ArrayList<>(); + exps.add(message); + typeAndExps = new AbstractMap.SimpleEntry<>(exps, msgType); + msgTypeMap.put(0, typeAndExps); + expToMessage.put(System.identityHashCode(message), exps); + } else { + typeAndExps.getKey().add(message); + expToMessage.put(System.identityHashCode(message), typeAndExps.getKey()); + Map updateExps = getUpdateSet(updateFromMessage, typeAndExps.getKey()); + if (compareTypes(typeAndExps.getValue(), msgType)) { + typeAndExps.setValue(msgType); + for (Expression e : typeAndExps.getKey()) { + if (e != message) { + if (e instanceof Variable) { + ((Variable) e).setType(msgType); + updateExps.put(System.identityHashCode(e), e); + } + } + } + } else if (compareTypes(msgType, typeAndExps.getValue())) { + ((Variable) message).setType(typeAndExps.getValue()); + updateExps.put(System.identityHashCode(message), message); + } + } + } else if (message instanceof Term) { + Map, Type>> msgTypeMap = messages.get(rootCh); + if (msgTypeMap == null) { + msgTypeMap = new HashMap<>(); + messages.put(rootCh, msgTypeMap); + } + for (int i = 0; i < ((Term) message).getArity(); i++) { + Expression arg = ((Term) message).getChild(i); + Type argType = null; + if (arg instanceof Variable) { + argType = ((Variable) arg).getType(); + } else if (arg instanceof Term) { + argType = ((Term) arg).getType(); + } else { + continue; + } + Map.Entry, Type> typeAndExps = msgTypeMap.get(i); + if (typeAndExps == null) { + List exps = new ArrayList<>(); + exps.add(arg); + typeAndExps = new AbstractMap.SimpleEntry<>(exps, argType); + msgTypeMap.put(i, typeAndExps); + expToMessage.put(System.identityHashCode(arg), exps); + } else { + typeAndExps.getKey().add(arg); + expToMessage.put(System.identityHashCode(arg), typeAndExps.getKey()); + Map updateExps = getUpdateSet(updateFromMessage, typeAndExps.getKey()); + if (compareTypes(typeAndExps.getValue(), argType)) { + typeAndExps.setValue(argType); + for (Expression e : typeAndExps.getKey()) { + if (e != arg) { + if (e instanceof Variable) { + ((Variable) e).setType(argType); + updateExps.put(System.identityHashCode(e), e); + } + } + } + } else if (compareTypes(argType, typeAndExps.getValue())) { + if (arg instanceof Variable) { + ((Variable) arg).setType(typeAndExps.getValue()); + updateExps.put(System.identityHashCode(arg), arg); + } else if (arg instanceof Term) { + ((Term) arg).setType(typeAndExps.getValue()); + updateExps.put(System.identityHashCode(arg), arg); + } + } } } } } - rPath = rPath.getParent(); + for (Channel childCh: ch.getChildren()) { + groupForChannel(rootCh, childCh); + } } - } + }; + groupExpressionsByMessage.groupForChannel(ch, ch); + + // 1.4 Extract constraints on expressions in each term. + IExtractConstraintsOnExpressionsInTerm extractConstraintsOnExpressionsInTerm = new IExtractConstraintsOnExpressionsInTerm() { + public void extractForChannel(Channel ch) { + for (ChannelMember cm : ch.getChannelMembers()) { + StateTransition st = cm.getStateTransition(); + List terms = new ArrayList<>(); + if (st.getCurStateExpression() instanceof Term) { + Map subTerms = ((Term) st.getCurStateExpression()).getSubTerms(Term.class); + terms.addAll(subTerms.values()); + } + if (st.getMessageExpression() instanceof Term) { + Map subTerms = ((Term) st.getMessageExpression()).getSubTerms(Term.class); + terms.addAll(subTerms.values()); + } + if (st.getNextStateExpression() != null && st.getNextStateExpression() instanceof Term) { + Map subTerms = ((Term) st.getNextStateExpression()).getSubTerms(Term.class); + terms.addAll(subTerms.values()); + } + for (Term t : terms) { + Symbol symbol = t.getSymbol(); + if (symbol.equals(DataConstraintModel.cons) || symbol.equals(DataConstraintModel.set) || symbol.equals(DataConstraintModel.append)) { + // If the root symbol of the term is cons or set. + List consExps = new ArrayList<>(); + consExps.add(t); // list term + updateExpressionBelonging(expToConsOrSet, t, consExps); + if (symbol.equals(DataConstraintModel.cons)) { + // If the root symbol of the term is cons. + for (Expression e : t.getChildren()) { + consExps.add(e); + updateExpressionBelonging(expToConsOrSet, e, consExps); + } + } else if (symbol.equals(DataConstraintModel.append)) { + // If the root symbol of the term is append. + Expression e = t.getChildren().get(1); + consExps.add(e); // list element + updateExpressionBelonging(expToConsOrSet, e, consExps); + e = t.getChildren().get(0); + consExps.add(e); // list argument + updateExpressionBelonging(expToConsOrSet, e, consExps); + } else { + // If the root symbol of the term is set. + Expression e = t.getChildren().get(2); + consExps.add(e); // list element + updateExpressionBelonging(expToConsOrSet, e, consExps); + e = t.getChildren().get(0); + consExps.add(e); // list argument + updateExpressionBelonging(expToConsOrSet, e, consExps); + } + Type newType = getExpTypeIfUpdatable(t.getType(), consExps.get(2)); + if (newType != null) { + // If the type of the 2nd argument of cons (1st argument of set/append) is more concrete than the type of the term. + t.setType(newType); + Map updateCons = getUpdateSet(updateFromConsOrSet, consExps); + updateCons.put(System.identityHashCode(t), t); + } else { + Type arg2Type = null; + if (consExps.get(2) != null && consExps.get(2) instanceof Variable) { + arg2Type = ((Variable) consExps.get(2)).getType(); + if (compareTypes(arg2Type, t.getType())) { + // If the type of the term is more concrete than the type of the 2nd argument of cons (1st argument of set/append). + ((Variable) consExps.get(2)).setType(t.getType()); + Map updateCons = getUpdateSet(updateFromConsOrSet, consExps); + updateCons.put(System.identityHashCode(consExps.get(2)), consExps.get(2)); + } + } else if (consExps.get(2) != null && consExps.get(2) instanceof Term) { + arg2Type = ((Term) consExps.get(2)).getType(); + if (compareTypes(arg2Type, t.getType())) { + // If the type of the term is more concrete than the type of the 2nd argument of cons (1st argument of set/append). + ((Term) consExps.get(2)).setType(t.getType()); + Map updateCons = getUpdateSet(updateFromConsOrSet, consExps); + updateCons.put(System.identityHashCode(consExps.get(2)), consExps.get(2)); + } + } + } + Type newCompType = getExpTypeIfUpdatable(listComponentTypes.get(t.getType()), consExps.get(1)); + if (newCompType != null) { + // If the type of the 1st argument of cons (3rd argument of set) is more concrete than the type of list component. + Type newListType = listTypes.get(newCompType); + if (newListType == null) { + // Create new list type. + newListType = createNewListType(newCompType, DataConstraintModel.typeList); + } + t.setType(newListType); + Map updateCons = getUpdateSet(updateFromConsOrSet, consExps); + updateCons.put(System.identityHashCode(t), t); + if (consExps.get(2) != null && consExps.get(2) instanceof Variable) { + ((Variable) consExps.get(2)).setType(newListType); + updateCons.put(System.identityHashCode(consExps.get(2)), consExps.get(2)); + } else if (consExps.get(2) != null && consExps.get(2) instanceof Term) { + ((Term) consExps.get(2)).setType(newListType); + updateCons.put(System.identityHashCode(consExps.get(2)), consExps.get(2)); + } + } + consOrSet.put(System.identityHashCode(consExps), t.getType()); + } else if (symbol.equals(DataConstraintModel.head) || symbol.equals(DataConstraintModel.get)) { + // If the root symbol of the term is head or get. + List consExps = new ArrayList<>(); + Expression e = t.getChildren().get(0); + consExps.add(e); // list argument + updateExpressionBelonging(expToConsOrSet, e, consExps); + consExps.add(t); // list's component + updateExpressionBelonging(expToConsOrSet, t, consExps); + consExps.add(null); + Type listType = listTypes.get(t.getType()); + if (listType == null && t.getType() != null) { + // Create a new list type. + listType = createNewListType(t.getType(), DataConstraintModel.typeList); + } + Type newListType = getExpTypeIfUpdatable(listType, consExps.get(0)); + if (newListType != null) { + // If the type of the component of the 1st argument is more concrete than the type of the term. + Type newCompType = listComponentTypes.get(newListType); + if (newCompType != null) { + t.setType(newCompType); + Map updateCons = getUpdateSet(updateFromConsOrSet, consExps); + updateCons.put(System.identityHashCode(t), t); + } + consOrSet.put(System.identityHashCode(consExps), newListType); + } else { + // If the type of the term is more concrete than the type of the component of the 1st argument. + if (consExps.get(0) != null && consExps.get(0) instanceof Variable) { + ((Variable) consExps.get(0)).setType(listType); + Map updateCons = getUpdateSet(updateFromConsOrSet, consExps); + updateCons.put(System.identityHashCode(consExps.get(0)), consExps.get(0)); + } else if (consExps.get(0) != null && consExps.get(0) instanceof Term) { + ((Term) consExps.get(0)).setType(listType); + Map updateCons = getUpdateSet(updateFromConsOrSet, consExps); + updateCons.put(System.identityHashCode(consExps.get(0)), consExps.get(0)); + } + consOrSet.put(System.identityHashCode(consExps), listType); + } + } else if (symbol.equals(DataConstraintModel.tail)) { + // If the root symbol of the term is tail. + List consExps = new ArrayList<>(); + consExps.add(t); // list term + updateExpressionBelonging(expToConsOrSet, t, consExps); + consExps.add(null); // list's component + Expression e = t.getChildren().get(0); + consExps.add(e); // list argument + updateExpressionBelonging(expToConsOrSet, e, consExps); + Type newType = getExpTypeIfUpdatable(t.getType(), consExps.get(2)); + if (newType != null) { + // If the type of the argument is more concrete than the type of the term. + t.setType(newType); + Map updateCons = getUpdateSet(updateFromConsOrSet, consExps); + updateCons.put(System.identityHashCode(t), t); + } else { + Type argType = null; + if (consExps.get(2) != null && consExps.get(2) instanceof Variable) { + argType = ((Variable) consExps.get(2)).getType(); + if (compareTypes(argType, t.getType())) { + // If the type of the term is more concrete than the type of the argument. + ((Variable) consExps.get(2)).setType(t.getType()); + Map updateCons = getUpdateSet(updateFromConsOrSet, consExps); + updateCons.put(System.identityHashCode(consExps.get(2)), consExps.get(2)); + } + } else if (consExps.get(2) != null && consExps.get(2) instanceof Term) { + argType = ((Term) consExps.get(2)).getType(); + if (compareTypes(argType, t.getType())) { + // If the type of the term is more concrete than the type of the argument. + ((Term) consExps.get(2)).setType(t.getType()); + Map updateCons = getUpdateSet(updateFromConsOrSet, consExps); + updateCons.put(System.identityHashCode(consExps.get(2)), consExps.get(2)); + } + } + } + consOrSet.put(System.identityHashCode(consExps), t.getType()); + } else if (symbol.equals(DataConstraintModel.tuple)) { + // If the root symbol of the term is tuple. + List tupleExps = new ArrayList<>(); + List newArgTypesList = new ArrayList<>(); + tupleExps.add(t); // tuple term + updateExpressionBelonging(expToTuple, t, tupleExps); + for (Expression e : t.getChildren()) { + tupleExps.add(e); // tuple's component + updateExpressionBelonging(expToTuple, e, tupleExps); + if (e instanceof Variable) { + newArgTypesList.add(((Variable) e).getType()); + } else if (e instanceof Term) { + newArgTypesList.add(((Term) e).getType()); + } else { + newArgTypesList.add(null); + } + } + if (t.getType() == DataConstraintModel.typeTuple) { + Type newTupleType = tupleTypes.get(newArgTypesList); + if (newTupleType == null) { + // Create new tuple type; + newTupleType = createNewTupleType(newArgTypesList, DataConstraintModel.typeTuple); + } + // Update the type of the tuple term and record the updated expression. + t.setType(newTupleType); + Map updateExps = getUpdateSet(updateFromTuple, tupleExps); + updateExps.put(System.identityHashCode(t), t); + } + tuple.put(System.identityHashCode(tupleExps), t.getType()); + } else if (symbol.equals(DataConstraintModel.pair)) { + // If the root symbol of the term is pair. + List pairExps = new ArrayList<>(); + pairExps.add(t); // pair + updateExpressionBelonging(expToPair, t, pairExps); + if (t.getType() == DataConstraintModel.typePair) { + for (Expression e : t.getChildren()) { + pairExps.add(e); // left/right + updateExpressionBelonging(expToPair, e, pairExps); + Type newArgType = null; + if (e instanceof Variable) { + newArgType = (((Variable) e).getType()); + + } else if (e instanceof Term) { + newArgType = (((Term) e).getType()); + } + + if (newArgType != null) { + Type newPairType = pairTypes.get(newArgType); + if (newPairType != null) { + t.setType(newPairType); + Map updateExps = getUpdateSet(updateFromPair, pairExps); + updateExps.put(System.identityHashCode(t), t); + } + } + } + pair.put(System.identityHashCode(pairExps), t.getType()); + + } + } else if (symbol.equals(DataConstraintModel.fst)) { + // If the root symbol of the term is fst. + List tupleExps = new ArrayList<>(); + Expression arg = t.getChildren().get(0); + tupleExps.add(arg); // tuple argument + updateExpressionBelonging(expToTuple, arg, tupleExps); + tupleExps.add(t); // first component + updateExpressionBelonging(expToTuple, t, tupleExps); + tupleExps.add(null); // second component + Type argType = null; + if (arg instanceof Variable) { + argType = ((Variable) arg).getType(); + } else if (arg instanceof Term) { + argType = ((Term) arg).getType(); + } + Type newTupleType = DataConstraintModel.typeTuple; + if (argType == DataConstraintModel.typeTuple && t.getType() != null) { + List newCompTypeList = new ArrayList<>(); + newCompTypeList.add(t.getType()); + newCompTypeList.add(null); + newTupleType = tupleTypes.get(newCompTypeList); + if (newTupleType == null) { + // Create new tuple type; + newTupleType = createNewTupleType(newCompTypeList, DataConstraintModel.typeTuple); + } + } + if (argType != newTupleType && newTupleType != null) { + // Update the type of the tuple argument and record the updated expression. + if (arg instanceof Variable) { + ((Variable) arg).setType(newTupleType); + argType = newTupleType; + } else if (arg instanceof Term) { + ((Term) arg).setType(newTupleType); + argType = newTupleType; + } + Map updateExps = getUpdateSet(updateFromTuple, tupleExps); + updateExps.put(System.identityHashCode(arg), arg); + } + tuple.put(System.identityHashCode(tupleExps), argType); + } else if (symbol.equals(DataConstraintModel.snd)) { + // If the root symbol of the term is snd. + List tupleExps = new ArrayList<>(); + Expression arg = t.getChildren().get(0); + tupleExps.add(arg); // tuple argument + updateExpressionBelonging(expToTuple, arg, tupleExps); + tupleExps.add(null); // first component + tupleExps.add(t); // second component + updateExpressionBelonging(expToTuple, t, tupleExps); + Type argType = null; + if (arg instanceof Variable) { + argType = ((Variable) arg).getType(); + } else if (arg instanceof Term) { + argType = ((Term) arg).getType(); + } + Type newTupleType = DataConstraintModel.typeTuple; + if (argType == DataConstraintModel.typeTuple && t.getType() != null) { + List newCompTypeList = new ArrayList<>(); + newCompTypeList.add(null); + if (DataConstraintModel.typeTuple.isAncestorOf(t.getType())) { + List sndTypes = tupleComponentTypes.get(t.getType()); + if (sndTypes != null) { + for (Type t2: sndTypes) { + newCompTypeList.add(t2); + } + } else { + newCompTypeList.add(t.getType()); + } + } else { + newCompTypeList.add(t.getType()); + } + newTupleType = tupleTypes.get(newCompTypeList); + if (newTupleType == null) { + // Create new tuple type; + newTupleType = createNewTupleType(newCompTypeList, DataConstraintModel.typeTuple); + } + } + if (argType != newTupleType && newTupleType != null) { + // Update the type of the tuple argument and record the updated expression. + if (arg instanceof Variable) { + ((Variable) arg).setType(newTupleType); + argType = newTupleType; + } else if (arg instanceof Term) { + ((Term) arg).setType(newTupleType); + argType = newTupleType; + } + Map updateExps = getUpdateSet(updateFromTuple, tupleExps); + updateExps.put(System.identityHashCode(arg), arg); + } + tuple.put(System.identityHashCode(tupleExps), argType); + } else if (symbol.equals(DataConstraintModel.left)) { + // If the root symbol of the term is left. + List pairExps = new ArrayList<>(); + Expression arg = t.getChildren().get(0); + pairExps.add(arg); // pair + updateExpressionBelonging(expToPair, arg, pairExps); + pairExps.add(t); // left + updateExpressionBelonging(expToPair, t, pairExps); + pairExps.add(null); // right + Type argType = null; + if (arg instanceof Variable) { + argType = ((Variable) arg).getType(); + } else if (arg instanceof Term) { + argType = ((Term) arg).getType(); + } + Type newPairType = DataConstraintModel.typePair; + if (argType == DataConstraintModel.typePair && t.getType() != null) { + List newCompTypeList = new ArrayList<>(); + newCompTypeList.add(t.getType()); + newCompTypeList.add(null); + newPairType = pairTypes.get(newCompTypeList); + if (newPairType == null) { + // Create new tuple type; + newPairType = createNewTupleType(newCompTypeList, DataConstraintModel.typePair); + } + } + if (argType != newPairType && newPairType != null) { + if (arg instanceof Variable) { + ((Variable) arg).setType(newPairType); + argType = newPairType; + } else if (arg instanceof Term) { + ((Term) arg).setType(newPairType); + argType = newPairType; + } + Map updateExps = getUpdateSet(updateFromPair, pairExps); + updateExps.put(System.identityHashCode(arg), arg); + } + pair.put(System.identityHashCode(pairExps), argType); + } else if (symbol.equals(DataConstraintModel.right)) { + // If the root symbol of the term is right. + List pairExps = new ArrayList<>(); + Expression arg = t.getChildren().get(0); + pairExps.add(arg); // pair + updateExpressionBelonging(expToPair, arg, pairExps); + pairExps.add(null); // left + pairExps.add(t); // right + updateExpressionBelonging(expToPair, t, pairExps); + Type argType = null; + if (arg instanceof Variable) { + argType = ((Variable) arg).getType(); + } else if (arg instanceof Term) { + argType = ((Term) arg).getType(); + } + Type newPairType = DataConstraintModel.typePair; + if (argType == DataConstraintModel.typePair && t.getType() != null) { + List newCompTypeList = new ArrayList<>(); + newCompTypeList.add(null); + newCompTypeList.add(t.getType()); + newPairType = pairTypes.get(newCompTypeList); + if (newPairType == null) { + // Create new tuple type; + newPairType = createNewTupleType(newCompTypeList, DataConstraintModel.typePair); + } + } + if (argType != newPairType && newPairType != null) { + if (arg instanceof Variable) { + ((Variable) arg).setType(newPairType); + argType = newPairType; + } else if (arg instanceof Term) { + ((Term) arg).setType(newPairType); + argType = newPairType; + } + Map updateExps = getUpdateSet(updateFromPair, pairExps); + updateExps.put(System.identityHashCode(arg), arg); + } + pair.put(System.identityHashCode(pairExps), argType); + } else if (symbol.equals(DataConstraintModel.lookup)) { + // If the root symbol of the term is lookup. + List mapExps = new ArrayList<>(); + Expression arg1 = t.getChildren().get(0); // map + mapExps.add(arg1); + updateExpressionBelonging(expToMap, arg1, mapExps); + Expression arg2 = t.getChildren().get(1); // key + mapExps.add(arg2); + updateExpressionBelonging(expToMap, arg2, mapExps); + mapExps.add(t); // value + updateExpressionBelonging(expToMap, t, mapExps); + Type arg1Type = null; + if (arg1 instanceof Variable) { + arg1Type = ((Variable) arg1).getType(); + } else if (arg1 instanceof Term) { + arg1Type = ((Term) arg1).getType(); + } + List newCompTypeList = new ArrayList<>(); + if (arg2 instanceof Variable) { + newCompTypeList.add(((Variable) arg2).getType()); + } else if (arg2 instanceof Term) { + newCompTypeList.add(((Term) arg2).getType()); + } else { + newCompTypeList.add(null); + } + newCompTypeList.add(t.getType()); + if (arg1Type == DataConstraintModel.typeMap || arg1Type == null) { + Type newMapType = mapTypes.get(newCompTypeList); + if (newMapType == null) { + // Create new tuple type; + newMapType = createNewMapType(newCompTypeList, DataConstraintModel.typeMap); + } + // Update the type of the map argument and record the updated expression. + if (arg1 instanceof Variable) { + ((Variable) arg1).setType(newMapType); + arg1Type = newMapType; + } else if (arg1 instanceof Term) { + ((Term) arg1).setType(newMapType); + arg1Type = newMapType; + } + Map updateExps = getUpdateSet(updateFromMap, mapExps); + updateExps.put(System.identityHashCode(arg1), arg1); + } + map.put(System.identityHashCode(mapExps), arg1Type); + } else if (symbol.equals(DataConstraintModel.insert)) { + // If the root symbol of the term is insert. + List mapExps = new ArrayList<>(); + mapExps.add(t); // map + updateExpressionBelonging(expToMap, t, mapExps); + Expression arg1 = t.getChildren().get(1); // key + mapExps.add(arg1); + updateExpressionBelonging(expToMap, arg1, mapExps); + Expression arg2 = t.getChildren().get(2); // value + mapExps.add(arg2); + updateExpressionBelonging(expToMap, arg2, mapExps); + Expression arg0 = t.getChildren().get(0); // map + mapExps.add(arg0); + updateExpressionBelonging(expToMap, arg0, mapExps); + Type termType = t.getType(); + List newCompTypeList = new ArrayList<>(); + if (arg1 instanceof Variable) { + newCompTypeList.add(((Variable) arg1).getType()); + } else if (arg1 instanceof Term) { + newCompTypeList.add(((Term) arg1).getType()); + } else { + newCompTypeList.add(null); + } + if (arg2 instanceof Variable) { + newCompTypeList.add(((Variable) arg2).getType()); + } else if (arg2 instanceof Term) { + newCompTypeList.add(((Term) arg2).getType()); + } else { + newCompTypeList.add(null); + } + Type newTermType = getExpTypeIfUpdatable(termType, mapExps.get(3)); + if (newTermType != null) { + // If the type of the 1st argument of insert is more concrete than the type of the term. + t.setType(newTermType); + termType = newTermType; + Map updateExps = getUpdateSet(updateFromMap, mapExps); + updateExps.put(System.identityHashCode(t), t); + } else { + Type arg3Type = null; + if (mapExps.get(3) != null && mapExps.get(3) instanceof Variable) { + arg3Type = ((Variable) mapExps.get(3)).getType(); + if (compareTypes(arg3Type, t.getType())) { + // If the type of the term is more concrete than the type of the 1st argument of insert. + ((Variable) mapExps.get(3)).setType(t.getType()); + Map updateExps = getUpdateSet(updateFromMap, mapExps); + updateExps.put(System.identityHashCode(mapExps.get(3)), mapExps.get(3)); + } + } else if (mapExps.get(3) != null && mapExps.get(3) instanceof Term) { + arg3Type = ((Term) mapExps.get(3)).getType(); + if (compareTypes(arg3Type, t.getType())) { + // If the type of the term is more concrete than the type of the 1st argument of insert. + ((Term) mapExps.get(3)).setType(t.getType()); + Map updateExps = getUpdateSet(updateFromMap, mapExps); + updateExps.put(System.identityHashCode(mapExps.get(3)), mapExps.get(3)); + } + } + } + if (termType == DataConstraintModel.typeMap || termType == null) { + Type newMapType = mapTypes.get(newCompTypeList); + if (newMapType == null) { + // Create new tuple type; + newMapType = createNewMapType(newCompTypeList, DataConstraintModel.typeMap); + } + // Update the type of the map term and record the updated expression. + t.setType(newMapType); + Map updateExps = getUpdateSet(updateFromMap, mapExps); + updateExps.put(System.identityHashCode(t), t); + if (mapExps.get(3) != null && mapExps.get(3) instanceof Variable) { + ((Variable) mapExps.get(3)).setType(newMapType); + updateExps.put(System.identityHashCode(mapExps.get(3)), mapExps.get(3)); + } else if (mapExps.get(3) != null && mapExps.get(3) instanceof Term) { + ((Term) mapExps.get(3)).setType(newMapType); + updateExps.put(System.identityHashCode(mapExps.get(3)), mapExps.get(3)); + } + termType = newMapType; + } + map.put(System.identityHashCode(mapExps), termType); + } else if (symbol.equals(DataConstraintModel.addMember)) { + // If the root symbol of the term is addMember (addMember(json, key, value)). + List dotExps = new ArrayList<>(); + Expression jsonArg = t.getChildren().get(0); + Expression keyArg = t.getChildren().get(1); + Expression valueArg = t.getChildren().get(2); + dotExps.add(t); // json + updateExpressionBelonging(expToJson, t, dotExps); + dotExps.add(keyArg); // key + updateExpressionBelonging(expToJson, keyArg, dotExps); + dotExps.add(valueArg); // value + updateExpressionBelonging(expToJson, valueArg, dotExps); + dotExps.add(jsonArg); // json + updateExpressionBelonging(expToJson, jsonArg, dotExps); + Type jsonType = t.getType(); + Type valueType = null; + if (valueArg instanceof Variable) { + valueType = ((Variable) valueArg).getType(); + } else if (valueArg instanceof Term) { + valueType = ((Term) valueArg).getType(); + } + String keyName = null; + if (keyArg instanceof Constant) { + keyName = ((Constant) keyArg).getSymbol().getName(); + } + Type jsonArgType = null; + if (jsonArg instanceof Variable) { + jsonArgType = ((Variable) jsonArg).getType(); + } else if (jsonArg instanceof Term) { + jsonArgType = ((Term) jsonArg).getType(); + } + Type newJsonType = DataConstraintModel.typeJson; + if (jsonType == DataConstraintModel.typeJson && jsonArgType != null && keyName != null) { + Map newMemberTypes = new HashMap<>(((JsonType) jsonArgType).getMemberTypes()); + newMemberTypes.put(keyName, valueType); + newJsonType = jsonTypes.get(newMemberTypes); + if (newJsonType == null) { + // Create new json type; + newJsonType = createNewJsonType(newMemberTypes, DataConstraintModel.typeJson); + } + } + if (jsonType != newJsonType && newJsonType != null && !newJsonType.isAncestorOf(jsonType)) { + // Update the type of the json term and record the updated expression. + t.setType(newJsonType); + jsonType = newJsonType; + Map updateExps = getUpdateSet(updateFromJson, dotExps); + updateExps.put(System.identityHashCode(t), t); + } + json.put(System.identityHashCode(dotExps), jsonType); + } else if (symbol.equals(DataConstraintModel.dot)) { + // If the root symbol of the term is dot (json.property). + List dotExps = new ArrayList<>(); + Expression jsonArg = t.getChildren().get(0); + Expression keyArg = t.getChildren().get(1); + dotExps.add(jsonArg); // json + updateExpressionBelonging(expToJson, jsonArg, dotExps); + dotExps.add(keyArg); // key + updateExpressionBelonging(expToJson, keyArg, dotExps); + dotExps.add(t); // value + updateExpressionBelonging(expToJson, t, dotExps); + dotExps.add(null); // json + Type jsonType = null; + if (jsonArg instanceof Variable) { + jsonType = ((Variable) jsonArg).getType(); + } else if (jsonArg instanceof Term) { + jsonType = ((Term) jsonArg).getType(); + } + String keyName = null; + if (keyArg instanceof Constant) { + keyName = ((Constant) keyArg).getSymbol().getName(); + } + Type newJsonType = DataConstraintModel.typeJson; + if (jsonType == DataConstraintModel.typeJson && t.getType() != null && keyName != null) { + Map newMemberTypes = new HashMap<>(); + newMemberTypes.put(keyName, t.getType()); + newJsonType = jsonTypes.get(newMemberTypes); + if (newJsonType == null) { + // Create new json type; + newJsonType = createNewJsonType(newMemberTypes, DataConstraintModel.typeJson); + } + } + if (jsonType != newJsonType && newJsonType != null && !newJsonType.isAncestorOf(jsonType)) { + // Update the type of the json argument and record the updated expression. + if (jsonArg instanceof Variable) { + ((Variable) jsonArg).setType(newJsonType); + jsonType = newJsonType; + } else if (jsonArg instanceof Term) { + ((Term) jsonArg).setType(newJsonType); + jsonType = newJsonType; + } + Map updateExps = getUpdateSet(updateFromJson, dotExps); + updateExps.put(System.identityHashCode(jsonArg), jsonArg); + } + json.put(System.identityHashCode(dotExps), jsonType); + } else if (symbol.equals(DataConstraintModel.dotParam)) { + // If the root symbol of the term is dot (json.{param}). + List dotExps = new ArrayList<>(); + Expression jsonArg = t.getChildren().get(0); + Expression keyArg = t.getChildren().get(1); + dotExps.add(jsonArg); // json (list/map) + updateExpressionBelonging(expToJson, jsonArg, dotExps); + dotExps.add(null); // key + dotExps.add(t); // value + updateExpressionBelonging(expToJson, t, dotExps); + dotExps.add(null); // json + Type jsonType = null; + if (jsonArg instanceof Variable) { + jsonType = ((Variable) jsonArg).getType(); + } else if (jsonArg instanceof Term) { + jsonType = ((Term) jsonArg).getType(); + } + Type keyType = null; + if (keyArg instanceof Variable) { + keyType = ((Variable) keyArg).getType(); + } else if (keyArg instanceof Term) { + keyType = ((Term) keyArg).getType(); + } + Type newJsonType = null; + if (keyType == DataConstraintModel.typeInt) { + newJsonType = DataConstraintModel.typeList; + } else if (keyType == DataConstraintModel.typeString) { + newJsonType = DataConstraintModel.typeMap; + } + if (t.getType() != null) { + if ((jsonType == DataConstraintModel.typeList)) { + newJsonType = listTypes.get(t.getType()); + if (newJsonType == null) { + // Create new list type; + newJsonType = createNewListType(t.getType(), DataConstraintModel.typeList); + } + } else if (jsonType == DataConstraintModel.typeMap) { + List keyValueTypes = Arrays.asList(new Type[] {DataConstraintModel.typeString, t.getType()}); + newJsonType = mapTypes.get(keyValueTypes); + if (newJsonType == null) { + // Create new map type; + newJsonType = createNewMapType(keyValueTypes, DataConstraintModel.typeMap); + } + } + } + if (jsonType != newJsonType && newJsonType != null && !newJsonType.isAncestorOf(jsonType)) { + // Update the type of the json argument and record the updated expression. + if (jsonArg instanceof Variable) { + ((Variable) jsonArg).setType(newJsonType); + jsonType = newJsonType; + } else if (jsonArg instanceof Term) { + ((Term) jsonArg).setType(newJsonType); + jsonType = newJsonType; + } + Map updateExps = getUpdateSet(updateFromJson, dotExps); + updateExps.put(System.identityHashCode(jsonArg), jsonArg); + } + json.put(System.identityHashCode(dotExps), jsonType); + } else if (symbol.equals(DataConstraintModel.cond)) { + // If the root symbol of the term is if function. + Expression c1 = t.getChild(1); + Expression c2 = t.getChild(2); + List condTerms = new ArrayList<>(); + condTerms.add(t); + condTerms.add(c1); + condTerms.add(c2); + expToVariable.put(System.identityHashCode(t), condTerms); + expToVariable.put(System.identityHashCode(c1), condTerms); + expToVariable.put(System.identityHashCode(c2), condTerms); + Type condType = t.getType(); + Map updatedVars = getUpdateSet(updateFromVariable, condTerms); + Type child1Type = getExpTypeIfUpdatable(condType, c1); + if (child1Type != null) { + condType = child1Type; + t.setType(child1Type); + updatedVars.put(System.identityHashCode(t), t); + } else { + if (c1 instanceof Variable && compareTypes(((Variable) c1).getType(), condType)) { + ((Variable) c1).setType(condType); + updatedVars.put(System.identityHashCode(c1), c1); + } else if (c1 instanceof Term && compareTypes(((Term) c1).getType(), condType)) { + ((Term) c1).setType(condType); + updatedVars.put(System.identityHashCode(c1), c1); + } + } + Type child2Type = getExpTypeIfUpdatable(condType, c2); + if (child2Type != null) { + condType = child2Type; + t.setType(child2Type); + updatedVars.put(System.identityHashCode(t), t); + if (c1 instanceof Variable) { + ((Variable) c1).setType(child2Type); + updatedVars.put(System.identityHashCode(c1), c1); + } else if (c1 instanceof Term) { + ((Term) c1).setType(child2Type); + updatedVars.put(System.identityHashCode(c1), c1); + } + } else { + if (c2 instanceof Variable && compareTypes(((Variable) c2).getType(), condType)) { + ((Variable) c2).setType(condType); + updatedVars.put(System.identityHashCode(c2), c2); + } else if (c2 instanceof Term && compareTypes(((Term) c2).getType(), condType)) { + ((Term) c2).setType(condType); + updatedVars.put(System.identityHashCode(c2), c2); + } + } + variables.put(System.identityHashCode(condTerms), condType); + } else if (symbol.equals(DataConstraintModel.add) || symbol.equals(DataConstraintModel.sub) + || symbol.equals(DataConstraintModel.mul) || symbol.equals(DataConstraintModel.div)) { + // If the root symbol of the term is arithmetic operators. + Expression c1 = t.getChild(0); + Expression c2 = t.getChild(1); + List operands = new ArrayList<>(); + operands.add(t); + operands.add(c1); + operands.add(c2); + expToVariable.put(System.identityHashCode(t), operands); + expToVariable.put(System.identityHashCode(c1), operands); + expToVariable.put(System.identityHashCode(c2), operands); + Type opType = t.getType(); + Map updatedVars = getUpdateSet(updateFromVariable, operands); + Type child1Type = getExpTypeIfUpdatable(opType, c1); + if (child1Type != null) { + opType = child1Type; + t.setType(child1Type); + updatedVars.put(System.identityHashCode(t), t); + } else { + if (c1 instanceof Variable && compareTypes(((Variable) c1).getType(), opType)) { + ((Variable) c1).setType(opType); + updatedVars.put(System.identityHashCode(c1), c1); + } else if (c1 instanceof Term && compareTypes(((Term) c1).getType(), opType)) { + ((Term) c1).setType(opType); + updatedVars.put(System.identityHashCode(c1), c1); + } + } + Type child2Type = getExpTypeIfUpdatable(opType, c2); + if (child2Type != null) { + opType = child2Type; + t.setType(child2Type); + updatedVars.put(System.identityHashCode(t), t); + if (c1 instanceof Variable) { + ((Variable) c1).setType(child2Type); + updatedVars.put(System.identityHashCode(c1), c1); + } else if (c1 instanceof Term) { + ((Term) c1).setType(child2Type); + updatedVars.put(System.identityHashCode(c1), c1); + } + } else { + if (c2 instanceof Variable && compareTypes(((Variable) c2).getType(), opType)) { + ((Variable) c2).setType(opType); + updatedVars.put(System.identityHashCode(c2), c2); + } else if (c2 instanceof Term && compareTypes(((Term) c2).getType(), opType)) { + ((Term) c2).setType(opType); + updatedVars.put(System.identityHashCode(c2), c2); + } + } + variables.put(System.identityHashCode(operands), opType); + } else if (symbol.getSignature() != null + && symbol.getSignature()[0] == DataConstraintModel.typeList) { + // If the root symbol of the term is the list type (except for the cons function). + List consExps = new ArrayList<>(); + consExps.add(t); + expToVariable.put(System.identityHashCode(t), consExps); + Type condType = t.getType(); + Map updatedVars = getUpdateSet(updateFromVariable, consExps); + for (int i = 1; i < symbol.getSignature().length; i++) { + Type tc = symbol.getSignature()[i]; + if (tc == DataConstraintModel.typeList) { + Expression e = t.getChildren().get(i - 1); + Type newType = getExpTypeIfUpdatable(condType, e); + if (newType != null) { + condType = newType; + for (Expression e2 : consExps) { + if (e2 instanceof Variable) { + ((Variable) e2).setType(newType); + updatedVars.put(System.identityHashCode(e2), e2); + } else if (e2 instanceof Term) { + ((Term) e2).setType(newType); + updatedVars.put(System.identityHashCode(e2), e2); + } + } + } else { + if (e instanceof Variable && compareTypes(((Variable) e).getType(), condType)) { + ((Variable) e).setType(condType); + updatedVars.put(System.identityHashCode(e), e); + } else if (e instanceof Term && compareTypes(((Term) e).getType(), condType)) { + ((Term) e).setType(condType); + updatedVars.put(System.identityHashCode(e), e); + } + } + consExps.add(e); + expToVariable.put(System.identityHashCode(e), consExps); + } + } + variables.put(System.identityHashCode(consExps), condType); + } + } + } + for (Channel childCh: ch.getChildren()) { + extractForChannel(childCh); + } + } + }; + extractConstraintsOnExpressionsInTerm.extractForChannel(ch); + + // 1.5 Extract constraints on path parameters and resources. + IExtractConstraintsOnPathParametersAndResources extractConstraintsOnPathParametersAndResources = new IExtractConstraintsOnPathParametersAndResources() { + public void extractForChannel(Channel ch) { + for (ChannelMember cm : ch.getChannelMembers()) { + ResourcePath rPath = cm.getResource(); + while (rPath != null) { + Expression param = rPath.getLastParam(); + if (param != null) { + ResourceHierarchy parent = rPath.getResourceHierarchy().getParent(); + if (parent != null) { + List pathParams = resourcePathParams.get(parent); + if (pathParams == null) { + pathParams = new ArrayList<>(); + resourcePathParams.put(parent, pathParams); + } + pathParams.add(param); + expToPathParams.put(System.identityHashCode(param), pathParams); + Type parentType = parent.getResourceStateType(); + Type paramType = null; + if (param instanceof Variable) { + paramType = ((Variable) param).getType(); + } else if (param instanceof Term) { + paramType = ((Term) param).getType(); + } + if (paramType != null && parentType == null) { + if (paramType.equals(DataConstraintModel.typeString)) { + parentType = DataConstraintModel.typeMap; + } else if (paramType.equals(DataConstraintModel.typeInt)) { + parentType = DataConstraintModel.typeList; + } + if (parentType != null) { + parent.setResourceStateType(parentType); + updateFromResourceOwnership.add(parent); + } + } + } + } + rPath = rPath.getParent(); + } + } + for (Channel childCh: ch.getChildren()) { + extractForChannel(childCh); + } + } + }; + extractConstraintsOnPathParametersAndResources.extractForChannel(ch); } // 1.6 Extract constraints on resource hierarchies. @@ -2331,4 +2379,24 @@ } return false; } + + private static interface IGroupExpressionsByResource { + public void groupForChannel(Channel ch); + } + + private static interface IGroupExpressionsByVariable { + public void groupForChannel(Channel ch); + } + + private static interface IGroupExpressionsByMessage { + public void groupForChannel(Channel rootCh, Channel ch); + } + + private static interface IExtractConstraintsOnExpressionsInTerm { + public void extractForChannel(Channel ch); + } + + private static interface IExtractConstraintsOnPathParametersAndResources { + public void extractForChannel(Channel ch); + } } diff --git a/AlgebraicDataflowArchitectureModel/src/generators/JerseyCodeGenerator.java b/AlgebraicDataflowArchitectureModel/src/generators/JerseyCodeGenerator.java index 2d1c1c2..4f7d7ec 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/JerseyCodeGenerator.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/JerseyCodeGenerator.java @@ -140,7 +140,7 @@ List> fields = new ArrayList<>(); Map> descendantGetters = new HashMap<>(); Map getterAccessors = new HashMap<>(); - Map inputAccessors = new HashMap<>(); + Map> inputAccessors = new HashMap<>(); Map> constructorParams = new HashMap<>(); Map priorMemberForInputChannel = new HashMap<>(); @@ -835,7 +835,12 @@ if (resourcePath.length() > 0) { inputAccessor.addAnnotation(new Annotation("Path", "\"" + resourcePath + "\"")); } - inputAccessors.put(resourceNode.getResourceHierarchy(), inputAccessor); + Map nameToMethod = inputAccessors.get(resourceNode.getResourceHierarchy()); + if (nameToMethod == null) { + nameToMethod = new HashMap<>(); + inputAccessors.put(resourceNode.getResourceHierarchy(), nameToMethod); + } + nameToMethod.put(messageSymbol, inputAccessor); } } else if (message instanceof Variable) { // In each resource. @@ -899,7 +904,12 @@ if (resourcePath.length() > 0) { inputAccessor.addAnnotation(new Annotation("Path", "\"" + resourcePath + "\"")); } - inputAccessors.put(resourceNode.getResourceHierarchy(), inputAccessor); + Map nameToMethod = inputAccessors.get(resourceNode.getResourceHierarchy()); + if (nameToMethod == null) { + nameToMethod = new HashMap<>(); + inputAccessors.put(resourceNode.getResourceHierarchy(), nameToMethod); + } + nameToMethod.put(messageSymbol, inputAccessor); } } } @@ -970,7 +980,9 @@ // Add input accessors. for (ResourceHierarchy res: inputAccessors.keySet()) { if (rootRes.isAncestorOf(res)) { - rootComponent.addMethod(inputAccessors.get(res)); + for (MethodDeclaration inputAccessor: inputAccessors.get(res).values()) { + rootComponent.addMethod(inputAccessor); + } } } } diff --git a/AlgebraicDataflowArchitectureModel/src/models/algebra/Term.java b/AlgebraicDataflowArchitectureModel/src/models/algebra/Term.java index ac41269..07993fa 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/algebra/Term.java +++ b/AlgebraicDataflowArchitectureModel/src/models/algebra/Term.java @@ -84,11 +84,13 @@ thisClass = thisClass.getSuperclass(); } for (int i = 0; i < children.size(); i++) { - HashMap terms = children.get(i).getSubTerms(clazz); - for (Entry term: terms.entrySet()) { - Position pos = term.getKey(); - pos.addHeadOrder(i); - subTerms.put(pos, term.getValue()); + if (children.get(i) != null) { + HashMap terms = children.get(i).getSubTerms(clazz); + for (Entry term: terms.entrySet()) { + Position pos = term.getKey(); + pos.addHeadOrder(i); + subTerms.put(pos, term.getValue()); + } } } return subTerms; @@ -128,6 +130,8 @@ @Override public Expression unify(Expression another) { if (another instanceof Variable) return (Expression) this.clone(); + if (this instanceof Constant) return (Expression) this.clone(); + if (another instanceof Constant) return (Expression) another.clone(); if (another instanceof Term) { Term anotherTerm = (Term) another; if (!symbol.equals(anotherTerm.symbol)) return null; @@ -257,7 +261,11 @@ public Object clone() { Term newTerm = new Term(symbol); for (Expression e: children) { - newTerm.addChild((Expression) e.clone()); + if (e != null) { + newTerm.addChild((Expression) e.clone()); + } else { + newTerm.addChild(null); + } } newTerm.type = type; return newTerm; @@ -280,7 +288,11 @@ String exp = symbol.toString() + "("; String delimiter = ""; for (Expression e: children) { - exp += (delimiter + e.toString()); + if (e != null) { + exp += (delimiter + e.toString()); + } else { + exp += (delimiter + "null"); + } delimiter = ","; } return exp + ")"; diff --git a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/Channel.java b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/Channel.java index af144c8..2bec47e 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/Channel.java +++ b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/Channel.java @@ -60,6 +60,7 @@ public void addChild(Channel child) { children.add(child); child.parent = this; + child.refleshOutside(); } public List getSelectors() { @@ -84,6 +85,15 @@ public void addSelector(Selector selector) { selectors.add(selector); } + + public List getAllSelectorVariables() { + List allSelectorVariables = new ArrayList<>(); + if (parent != null) allSelectorVariables.addAll(parent.getAllSelectorVariables()); + for (Selector sel: selectors) { + allSelectorVariables.add(sel.getExpression()); + } + return allSelectorVariables; + } public Set getChannelMembers() { return channelMembers; @@ -115,6 +125,28 @@ } } + public void refleshOutside() { + for (ChannelMember channelMember: channelMembers) { + if (getAllSelectors().size() > 0) { + Set params = new HashSet<>(); + for (Selector s: getAllSelectors()) { + params.add(s.getExpression()); + } + if (!params.containsAll(channelMember.getResource().getPathParams())) { + channelMember.setOutside(true); + } else { + channelMember.setOutside(false); + } + } else { + if (channelMember.getResource().getPathParams().size() == 0) { + channelMember.setOutside(false); + } else { + channelMember.setOutside(true); + } + } + } + } + public void removeChannelMember(ResourcePath res) { for (ChannelMember cm: channelMembers) { if (cm.getResource() == res) { diff --git a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/DataConstraintModel.java b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/DataConstraintModel.java index e44c50c..858ecb4 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/DataConstraintModel.java +++ b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/DataConstraintModel.java @@ -962,7 +962,7 @@ lookup.setSignature(new Type[] {null, typeMap, null}); addMember.setSignature(new Type[] {typeJson, typeJson, typeString, null}); dot.setSignature(new Type[] {null, typeJson, typeString}); - dotParam.setSignature(new Type[] {null, null, null}); + dotParam.setSignature(new Type[] {null, typeJson, null}); pi.setSignature(new Type[] {typeDouble}); E.setSignature(new Type[] {typeDouble}); sqrt.setSignature(new Type[] {typeDouble, typeDouble}); diff --git a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/JsonAccessor.java b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/JsonAccessor.java index e7cadb5..30a7465 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/JsonAccessor.java +++ b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/JsonAccessor.java @@ -21,24 +21,11 @@ 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 reduce() { Expression reducedTerm = super.reduce(); if (reducedTerm instanceof Term) { - if (symbol.equals(DataConstraintModel.dot) && getChildren().size() >= 2) { + if ((symbol == DataConstraintModel.dot || symbol == DataConstraintModel.dotParam) && getChildren().size() >= 2) { // this term is `json.key`. Expression expJson = getChild(0); Expression expKey = getChild(1); @@ -54,12 +41,21 @@ if (json instanceof JsonTerm) { return ((JsonTerm) json).get(key); } - if (!json.getSymbol().equals(DataConstraintModel.addMember)) return null; - if (json.getChild(1).equals(key)) { - return json.getChild(2); + if (json.getSymbol().equals(DataConstraintModel.addMember) || json.getSymbol().equals(DataConstraintModel.set)) { + if (json.getChild(1).equals(key)) { + Expression value = json.getChild(2); + if (value == null) { + return new Constant(DataConstraintModel.null_); + } + return value; + } + if (json.getChild(0) == null + || (json.getChild(0) instanceof Term && + (((Term) json.getChild(0)).getSymbol().equals(DataConstraintModel.null_)) + || ((Term) json.getChild(0)).getSymbol().equals(DataConstraintModel.nil))) return null; + return getValue((Term) json.getChild(0), key); } - if (json.getChild(0) == null || json.getChild(0).equals(DataConstraintModel.nil)) return null; - return getValue((Term) json.getChild(0), key); + return new Constant(DataConstraintModel.null_); } @Override @@ -69,15 +65,15 @@ int i = targetPos.removeHeadOrder(); Symbol[] inverseSymbols = symbol.getInverses(); if (i == 0) { - if (symbol.equals(DataConstraintModel.dot) && getChildren().size() >= 2) { + if (symbol == DataConstraintModel.dot && getChildren().size() >= 2) { // this term is `json.key`. Expression expJson = getChild(0); Expression expKey = getChild(1); - JsonType jsonType = null; + Type jsonType = null; if (expJson instanceof Variable) { - jsonType = (JsonType) ((Variable) expJson).getType(); + jsonType = ((Variable) expJson).getType(); } else if (expJson instanceof Term) { - jsonType = (JsonType) ((Term) expJson).getType(); + jsonType = ((Term) expJson).getType(); } String keyName = null; if (expKey instanceof Constant) { @@ -89,8 +85,11 @@ Set keySet = new HashSet<>(); if (jsonType == null || jsonType == DataConstraintModel.typeJson) { keySet.add(keyName); - } else { - keySet.addAll(jsonType.getKeys()); + } else if (jsonType instanceof JsonType) { + keySet.addAll(((JsonType) jsonType).getKeys()); + if (keySet.size() == 0) { + keySet.add(keyName); + } } for (String key: keySet) { Term addMemberTerm = new Term(DataConstraintModel.addMember); // addMember(jsonTerm, key, v) @@ -106,7 +105,7 @@ LambdaAbstraction lambdaAbstraction = new LambdaAbstraction(var, jsonTerm); // v -> addMember(jsonTerm, key, v) inverseSymbols = new Symbol[] { lambdaAbstraction }; } - } else if (symbol.equals(DataConstraintModel.dotParam) && getChildren().size() >= 2) { + } else if (symbol == DataConstraintModel.dotParam && getChildren().size() >= 2) { // this term is `json.{param}`. Expression expListOrMap = getChild(0); Expression expKey = getChild(1); @@ -118,9 +117,9 @@ } Type keyType = null; if (expKey instanceof Variable) { - keyType = (JsonType) ((Variable) expKey).getType(); + keyType = ((Variable) expKey).getType(); } else if (expKey instanceof Term) { - keyType = (JsonType) ((Term) expKey).getType(); + keyType = ((Term) expKey).getType(); } if (jsonType != null && keyType != null) { if (DataConstraintModel.typeList.isAncestorOf(jsonType) || keyType.equals(DataConstraintModel.typeInt)) { diff --git a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/JsonTerm.java b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/JsonTerm.java index 5762940..8ccdfd5 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/JsonTerm.java +++ b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/JsonTerm.java @@ -1,6 +1,7 @@ package models.dataConstraintModel; import java.util.HashMap; +import java.util.HashSet; import java.util.Map; import java.util.Set; @@ -42,6 +43,30 @@ } @Override + public Expression unify(Expression another) { + if (another instanceof JsonTerm) { + JsonTerm anotherTerm = (JsonTerm) another; + JsonTerm unifiedTerm = new JsonTerm(); + Set keySet = new HashSet<>(); + keySet.addAll(this.keySet()); + keySet.addAll(anotherTerm.keySet()); + for (String key: keySet) { + if (this.keySet().contains(key)) { + if (anotherTerm.keySet().contains(key)) { + unifiedTerm.addMember(key, this.get(key).unify(anotherTerm.get(key))); + } else { + unifiedTerm.addMember(key, this.get(key)); + } + } else { + unifiedTerm.addMember(key, anotherTerm.get(key)); + } + } + return unifiedTerm; + } + return this; + } + + @Override public Object clone() { JsonTerm newTerm = new JsonTerm(); for (Expression e: children) { diff --git a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/ListTerm.java b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/ListTerm.java index 91dd47d..afc4212 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/ListTerm.java +++ b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/ListTerm.java @@ -1,7 +1,5 @@ package models.dataConstraintModel; -import java.util.HashMap; - import models.algebra.Expression; import models.algebra.Symbol; import models.algebra.Term; @@ -26,6 +24,20 @@ } @Override + public Expression unify(Expression another) { + if (another instanceof ListTerm) { + ListTerm anotherTerm = (ListTerm) another; + if (children.size() != anotherTerm.children.size()) return null; + ListTerm unifiedTerm = new ListTerm(); + for (int i = 0; i < children.size(); i++) { + unifiedTerm.addChild(children.get(i).unify(anotherTerm.children.get(i))); + } + return unifiedTerm; + } + return this; + } + + @Override public Object clone() { ListTerm newTerm = new ListTerm(); for (Expression e: children) { diff --git a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/MapTerm.java b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/MapTerm.java index 0badbd1..18f2c9b 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/MapTerm.java +++ b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/MapTerm.java @@ -1,6 +1,7 @@ package models.dataConstraintModel; import java.util.HashMap; +import java.util.HashSet; import java.util.Map; import java.util.Set; @@ -41,6 +42,30 @@ } @Override + public Expression unify(Expression another) { + if (another instanceof MapTerm) { + MapTerm anotherTerm = (MapTerm) another; + MapTerm unifiedTerm = new MapTerm(); + Set keySet = new HashSet<>(); + keySet.addAll(this.keySet()); + keySet.addAll(anotherTerm.keySet()); + for (String key: keySet) { + if (this.keySet().contains(key)) { + if (anotherTerm.keySet().contains(key)) { + unifiedTerm.insert(key, this.get(key).unify(anotherTerm.get(key))); + } else { + unifiedTerm.insert(key, this.get(key)); + } + } else { + unifiedTerm.insert(key, anotherTerm.get(key)); + } + } + return unifiedTerm; + } + return this; + } + + @Override public Object clone() { MapTerm newTerm = new MapTerm(); for (Expression e: children) { diff --git a/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/DataTransferChannel.java b/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/DataTransferChannel.java index 46bf393..d6a81d9 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/DataTransferChannel.java +++ b/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/DataTransferChannel.java @@ -22,6 +22,7 @@ import models.dataConstraintModel.ChannelMember; import models.dataConstraintModel.ResourcePath; import models.dataConstraintModel.Selector; +import parser.Parser; public class DataTransferChannel extends Channel { protected Set inputChannelMembers = null; @@ -343,6 +344,11 @@ return resourcePaths; } + /** + * Get the dependency from the values of the 'path parameters' of a channel member to the state values of other channel members. + * + * @return a map from a depending channel member to depended channel members + */ public Map> getMemberDependency() { Map> dependency = new HashMap<>(); @@ -358,7 +364,7 @@ for (ChannelMember otherCm: substitutedPositionsInMessage.keySet()) { for (Position otherPos: substitutedPositionsInMessage.get(otherCm)) { for (Position thisPos: dependingVarPosInMessage) { - if (thisPos.isAncestorOf(otherPos)) { + if (thisPos.isAncestorOf(otherPos) && otherCm != cm) { dependingChannelMembers.add(otherCm); break; } @@ -376,7 +382,7 @@ for (ChannelMember otherCm: substitutedPositionsInMessage.keySet()) { for (Position otherPos: substitutedPositionsInMessage.get(otherCm)) { for (Position thisPos: dependingVarPosInMessage) { - if (thisPos.isAncestorOf(otherPos)) { + if (thisPos.isAncestorOf(otherPos) && otherCm != cm) { dependingChannelMembers.add(otherCm); break; } @@ -394,7 +400,7 @@ for (ChannelMember otherCm: substitutedPositionsInMessage.keySet()) { for (Position otherPos: substitutedPositionsInMessage.get(otherCm)) { for (Position thisPos: dependingVarPosInMessage) { - if (thisPos.isAncestorOf(otherPos)) { + if (thisPos.isAncestorOf(otherPos) && otherCm != cm) { dependingChannelMembers.add(otherCm); break; } @@ -527,7 +533,7 @@ return channelMembersMessageDependsOn; } - public ResourcePath fillOutsideResourcePath(ResourcePath resource, Term unifiedMessage, Expression messageTerm, Set dependingVarPosInMessage) + public ResourcePath fillOutsideResourcePath(ResourcePath resource, Expression unifiedMessage, Expression messageTerm, Set dependingVarPosInMessage) throws ResolvingMultipleDefinitionIsFutureWork { ResourcePath filledResourcePath = new ResourcePath(resource); @@ -615,9 +621,13 @@ public String toString() { String channelSource = ""; if (isNative()) { - channelSource += "native "; + channelSource += Parser.NATIVE + " "; } - channelSource += "channel " + getChannelName(); + if (parent == null) { + channelSource += Parser.CHANNEL + " " + getChannelName(); + } else { + channelSource += Parser.SUB_CHANNEL + " " + getChannelName(); + } if (getSelectors().size() > 0) { channelSource += "("; String delimitor = ""; @@ -629,13 +639,16 @@ } channelSource += " {\n"; for (ChannelMember inputMember: inputChannelMembers) { - channelSource += "\t in " + inputMember + "\n"; + channelSource += "\t " + Parser.IN + " " + inputMember + "\n"; } for (ChannelMember refMember: referenceChannelMembers) { - channelSource += "\t ref " + refMember + "\n"; + channelSource += "\t " + Parser.REF + " " + refMember + "\n"; } for (ChannelMember outputMember: outputChannelMembers) { - channelSource += "\t out " + outputMember + "\n"; + channelSource += "\t " + Parser.OUT + " " + outputMember + "\n"; + } + for (Channel childCh: getChildren()) { + channelSource += childCh.toString(); } channelSource += "}\n"; return channelSource; diff --git a/AlgebraicDataflowArchitectureModel/src/parser/Parser.java b/AlgebraicDataflowArchitectureModel/src/parser/Parser.java index 60f5a55..90b1174 100644 --- a/AlgebraicDataflowArchitectureModel/src/parser/Parser.java +++ b/AlgebraicDataflowArchitectureModel/src/parser/Parser.java @@ -46,7 +46,7 @@ public static final String IN = "in"; public static final String OUT = "out"; public static final String REF = "ref"; - public static final String SUB_CHANNEL = "sub"; + public static final String SUB_CHANNEL = "for"; public static final String NATIVE = "native"; public static final String LEFT_CURLY_BRACKET = "{"; public static final String RIGHT_CURLY_BRACKET = "}"; @@ -454,7 +454,7 @@ paramType = ((Term) paramTerm).getType(); } Term term = null; - if (paramType != null && DataTransferModel.typeInt.isAncestorOf(paramType)) { + if (literalOrLeftCurlyBracket.equals(LEFT_CURLY_BRACKET)) { term = new JsonAccessor(DataTransferModel.dotParam); } else { term = new JsonAccessor(DataTransferModel.dot); @@ -464,6 +464,17 @@ expressions.add(term); operator = stream.checkNext(); if (operator == null) break; + if (operator.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); + } + term.setType(type); + break; + } } if (operator == null) { break; diff --git a/AlgebraicDataflowArchitectureModel/src/simulator/ChannelState.java b/AlgebraicDataflowArchitectureModel/src/simulator/ChannelState.java index ce4424e..4178d73 100644 --- a/AlgebraicDataflowArchitectureModel/src/simulator/ChannelState.java +++ b/AlgebraicDataflowArchitectureModel/src/simulator/ChannelState.java @@ -10,6 +10,12 @@ import models.dataConstraintModel.Selector; import models.dataFlowModel.DataTransferChannel; +/** + * State of a channel, which represents the map from the values of the depended channel selectors to those of the depending channel selectors + * + * @author Nitta + * + */ public class ChannelState implements Cloneable { private DataTransferChannel channel; private ReferenceStructure referenceStructure; @@ -24,7 +30,7 @@ public Map getDependingParamAndValues(List channelValues) { if (referenceStructure == null) { - return null; + return new HashMap<>(); } return referenceStructure.getDependingParamAndValues(channelValues); } @@ -45,6 +51,13 @@ return referenceStructure.getDependedChannelSelectorValues(dependingVarToVal); } + /** + * Add a value of a depending channel selector + * + * @param channelValues the values of depended channel selectors + * @param dependingVariable a depending channel selector + * @param itsValue its new value + */ public void addDependingParamAndValue(List channelValues, Expression dependingVariable, Expression itsValue) { if (referenceStructure == null) { referenceStructure = new ReferenceStructure(); @@ -54,7 +67,7 @@ public Object clone() { ChannelState newChannelState = new ChannelState(channel); - newChannelState.referenceStructure = (ReferenceStructure) referenceStructure.clone(); + if (referenceStructure != null) newChannelState.referenceStructure = (ReferenceStructure) referenceStructure.clone(); return newChannelState; } @@ -72,7 +85,7 @@ if (subStructure.getDependentParamAndValues() == null) { subStructure = subStructure.getReferenceStructure(chVal); } else { - return null; + return new HashMap<>(); } } return subStructure.getDependentParamAndValues(); diff --git a/AlgebraicDataflowArchitectureModel/src/simulator/Event.java b/AlgebraicDataflowArchitectureModel/src/simulator/Event.java index f263fe9..23dfafa 100644 --- a/AlgebraicDataflowArchitectureModel/src/simulator/Event.java +++ b/AlgebraicDataflowArchitectureModel/src/simulator/Event.java @@ -14,6 +14,8 @@ import models.algebra.Position; import models.algebra.Term; import models.algebra.UnificationFailed; +import models.algebra.Variable; +import models.dataConstraintModel.Channel; import models.dataConstraintModel.ChannelMember; import models.dataConstraintModel.ResourcePath; import models.dataConstraintModel.Selector; @@ -21,6 +23,12 @@ import models.dataFlowModel.DataTransferChannel.IResourceStateAccessor; import models.dataFlowModel.ResolvingMultipleDefinitionIsFutureWork; +/** + * Event occurred at a channel + * + * @author Nitta + * + */ public class Event { private DataTransferChannel channel; private Expression message; @@ -31,10 +39,18 @@ private List> channelSelectorAndValues = new ArrayList<>(); private Map dependingParameters = new HashMap<>(); private Set outputResources = new HashSet<>(); - private Set succEvents = new HashSet<>(); - private Map> channelSelectorToInputResourcePathParam = new HashMap<>(); - private Map> channelSelectorToOutputResourcePathParam = new HashMap<>(); + private Set childEvents = new HashSet<>(); + private Map>>> channelSelectorToInputOrReferenceResourcePathParam = new HashMap<>(); + private Map>>> channelSelectorToOutputResourcePathParam = new HashMap<>(); + /** + * Constructor for an input event channel + * + * @param channel an input event channel + * @param message an message for the channel + * @param outputResPath an output side resource path of the channel + * @param outputResource an output side resource of the channel + */ public Event(DataTransferChannel channel, Expression message, ResourcePath outputResPath, Resource outputResource) { this.channel = channel; this.message = message; @@ -42,16 +58,16 @@ this.outputResources.add(outputResource); connectChannelSelectorAndPathParameters(); - // Extract channel parameters from the output resource. + // Extract the values of the channel selectors from the output resource. List channelSelectors = channel.getAllSelectors(); for (Selector sel: channelSelectors) { - int paramIdx = channelSelectorToOutputResourcePathParam.get(sel).get(outputResPath); + Map.Entry> paramIdxAndPos = channelSelectorToOutputResourcePathParam.get(sel).get(outputResPath); Resource ancestor = outputResource; int idx = outputResPath.getPathParams().size(); while (ancestor != null) { if (ancestor.getResourceHierarchy().getNumParameters() > 0) { idx--; - if (idx == paramIdx) break; + if (idx == paramIdxAndPos.getKey()) break; } ancestor = ancestor.getParent(); } @@ -59,6 +75,13 @@ } } + /** + * Constructor for a non-event channel + * + * @param channel a non-event channel + * @param inputResPath an input side resource path of the channel + * @param inputResource an input side resource of the channel + */ public Event(DataTransferChannel channel, ResourcePath inputResPath, Resource inputResource) { this.channel = channel; this.isInput = false; @@ -66,18 +89,18 @@ this.inputResource = inputResource; connectChannelSelectorAndPathParameters(); - // Extract channel parameters from the input resource. + // Extract the values of the channel selectors from the input resource. List channelSelectors = channel.getAllSelectors(); for (Selector sel: channelSelectors) { if (inputResPath != null) { - Integer paramIdx = channelSelectorToInputResourcePathParam.get(sel).get(inputResPath); - if (paramIdx != null) { + Map.Entry> paramIdxAndPos = channelSelectorToInputOrReferenceResourcePathParam.get(sel).get(inputResPath); + if (paramIdxAndPos != null) { Resource ancestor = inputResource; int idx = inputResPath.getPathParams().size(); while (ancestor != null) { if (ancestor.getResourceHierarchy().getNumParameters() > 0) { idx--; - if (idx == paramIdx) break; + if (idx == paramIdxAndPos.getKey()) break; } ancestor = ancestor.getParent(); } @@ -87,6 +110,15 @@ } } + /** + * Constructor for a non-event channel + * + * @param channel a non-event channel + * @param inputResPath an input side resource path of the channel + * @param inputResource an input side resource of the channel + * @param channelSelectorValues the values of depended channel selectors + * @param dependingVarToVal the values of depending channel selectors + */ public Event(DataTransferChannel channel, ResourcePath inputResPath, Resource inputResource, List channelSelectorValues, Map dependingVarToVal) { this.channel = channel; this.isInput = false; @@ -94,7 +126,7 @@ this.inputResource = inputResource; connectChannelSelectorAndPathParameters(); - // Extract channel parameters from the input resource. + // Extract the values of the channel selectors from channelSelectorValues. List channelSelectors = channel.getAllSelectors(); for (int i = 0; i < channelSelectors.size(); i++) { Selector sel = channelSelectors.get(i); @@ -106,26 +138,54 @@ private void connectChannelSelectorAndPathParameters() { List channelSelectors = channel.getAllSelectors(); for (Selector sel: channelSelectors) { - for (ResourcePath resPath: channel.getInputResources()) { - int paramIdx = resPath.getPathParams().indexOf(sel.getExpression()); - if (paramIdx >= 0) { - Map pathToIdx = channelSelectorToInputResourcePathParam.get(sel); - if (pathToIdx == null) { - pathToIdx = new HashMap<>(); - channelSelectorToInputResourcePathParam.put(sel, pathToIdx); + Set inputAndReferenceResPaths = new HashSet<>(channel.getInputResources()); + inputAndReferenceResPaths.addAll(channel.getReferenceResources()); + for (ResourcePath resPath: inputAndReferenceResPaths) { + for (int paramIdx = 0; paramIdx < resPath.getPathParams().size(); paramIdx++) { + Expression pathParam = resPath.getPathParams().get(paramIdx); + if (pathParam.contains(sel.getExpression())) { + for (Map.Entry posAndVar: pathParam.getVariables().entrySet()) { + Position p = posAndVar.getKey(); + Variable v = posAndVar.getValue(); + if (v.equals(sel.getExpression())) { + Map>> pathToIdxAndPos = channelSelectorToInputOrReferenceResourcePathParam.get(sel); + if (pathToIdxAndPos == null) { + pathToIdxAndPos = new HashMap<>(); + channelSelectorToInputOrReferenceResourcePathParam.put(sel, pathToIdxAndPos); + } + Map.Entry> idxAndPos = pathToIdxAndPos.get(resPath); + if (idxAndPos == null) { + idxAndPos = new AbstractMap.SimpleEntry<>(paramIdx, new HashSet<>()); + pathToIdxAndPos.put(resPath, idxAndPos); + } + idxAndPos.getValue().add(p); + } + } } - pathToIdx.put(resPath, paramIdx); } } for (ResourcePath resPath: channel.getOutputResources()) { - int paramIdx = resPath.getPathParams().indexOf(sel.getExpression()); - if (paramIdx >= 0) { - Map pathToIdx = channelSelectorToOutputResourcePathParam.get(sel); - if (pathToIdx == null) { - pathToIdx = new HashMap<>(); - channelSelectorToOutputResourcePathParam.put(sel, pathToIdx); + for (int paramIdx = 0; paramIdx < resPath.getPathParams().size(); paramIdx++) { + Expression pathParam = resPath.getPathParams().get(paramIdx); + if (pathParam.contains(sel.getExpression())) { + for (Map.Entry posAndVar: pathParam.getVariables().entrySet()) { + Position p = posAndVar.getKey(); + Variable v = posAndVar.getValue(); + if (v.equals(sel.getExpression())) { + Map>> pathToIdxAndPos = channelSelectorToOutputResourcePathParam.get(sel); + if (pathToIdxAndPos == null) { + pathToIdxAndPos = new HashMap<>(); + channelSelectorToOutputResourcePathParam.put(sel, pathToIdxAndPos); + } + Map.Entry> idxAndPos = pathToIdxAndPos.get(resPath); + if (idxAndPos == null) { + idxAndPos = new AbstractMap.SimpleEntry<>(paramIdx, new HashSet<>()); + pathToIdxAndPos.put(resPath, idxAndPos); + } + idxAndPos.getValue().add(p); + } + } } - pathToIdx.put(resPath, paramIdx); } } } @@ -170,8 +230,36 @@ return dependingParameters; } + public void addChild(Event child) { + childEvents.add(child); + } - public Term updateDependingParameters(IResourceStateValueProvider resourceStateValueProvider) { + public Set getChildren() { + return childEvents; + } + + /** + * Construct channel message, collect descendant events of this event and update the values of the depending channel selectors + * + * @param resourceStateValueProvider a resourceStateValueProvider to provide current and next resource states + * @return calculated message constraint by this event + */ + public Expression constructMessageAndDescendantEvents(IResourceStateValueProvider resourceStateValueProvider, boolean doesUpdateDependingParameters) { + + try { + Map> substitutedPositionsInMessageFromChannels = new HashMap<>(); + return constructMessageAndDesdendantEvents(resourceStateValueProvider, substitutedPositionsInMessageFromChannels, doesUpdateDependingParameters); + } catch (ResolvingMultipleDefinitionIsFutureWork | InvalidMessage | UnificationFailed e) { + e.printStackTrace(); + } + return null; + } + + private Expression constructMessageAndDesdendantEvents(IResourceStateValueProvider resourceStateValueProvider, + Map> substitutedPositionsInMessageFromChannels, boolean doesUpdateDependingParameters) + throws InvalidMessage, ResolvingMultipleDefinitionIsFutureWork, UnificationFailed { + Expression unifiedMessage = null; + Expression messageConstraint = null; IResourceStateAccessor resouceStateAccessor = new IResourceStateAccessor() { @Override public Expression getCurrentStateAccessorFor(ChannelMember target, ChannelMember from) { @@ -191,42 +279,36 @@ return resourceStateValueProvider.getCurrentStateValueOf(resId); } }; - - try { - Map> substitutedPositionsInMessageFromChannels = new HashMap<>(); - Term unifiedMessage = null; - - // Calculate message constraints from leaf channel members on the channel member dependency graph. - Map> dependency = channel.getMemberDependency(); - if (dependency.size() == 0) { - // No channel member dependency. - Expression messageConstraint = null; - for (ChannelMember channelMember: channel.getInputChannelMembers()) { - // Calculate message constraint from an input state transition - messageConstraint = channel.calcMessageConstraintForInputMember(channelMember, null, resouceStateAccessor, null, substitutedPositionsInMessageFromChannels); + + // 1. Calculate message constraints from leaf channel members on the 'channel member dependency graph'. + Map> dependency = channel.getMemberDependency(); + if (dependency.size() == 0) { + // No channel member dependency. + for (ChannelMember channelMember: channel.getInputChannelMembers()) { + // Calculate message constraint from an input state transition + messageConstraint = channel.calcMessageConstraintForInputMember(channelMember, null, resouceStateAccessor, null, substitutedPositionsInMessageFromChannels); + if (unifiedMessage == null) { + unifiedMessage = messageConstraint; + } else { + unifiedMessage = unifiedMessage.unify(messageConstraint); if (unifiedMessage == null) { - unifiedMessage = (Term) messageConstraint; - } else { - unifiedMessage = (Term) unifiedMessage.unify(messageConstraint); - if (unifiedMessage == null) { - throw new UnificationFailed(); - } + throw new UnificationFailed(); } } - for (ChannelMember channelMember: channel.getReferenceChannelMembers()) { - // Calculate message constraint from a reference state transition - messageConstraint = channel.calcMessageConstraintForReferenceMember(channelMember, null, resouceStateAccessor, null, substitutedPositionsInMessageFromChannels); - if (unifiedMessage == null) { - unifiedMessage = (Term) messageConstraint; - } else { - unifiedMessage = (Term) unifiedMessage.unify(messageConstraint); - if (unifiedMessage == null) { - throw new UnificationFailed(); - } - } - } - return unifiedMessage; } + for (ChannelMember channelMember: channel.getReferenceChannelMembers()) { + // Calculate message constraint from a reference state transition + messageConstraint = channel.calcMessageConstraintForReferenceMember(channelMember, null, resouceStateAccessor, null, substitutedPositionsInMessageFromChannels); + if (unifiedMessage == null) { + unifiedMessage = messageConstraint; + } else { + unifiedMessage = unifiedMessage.unify(messageConstraint); + if (unifiedMessage == null) { + throw new UnificationFailed(); + } + } + } + } else { Set toResolve = new HashSet<>(); Set resolved = new HashSet<>(); for (Set depended: dependency.values()) { @@ -235,9 +317,8 @@ for (ChannelMember depending: dependency.keySet()) { toResolve.remove(depending); } - Expression messageConstraint = null; if ((messageConstraint = getMessage()) instanceof Term) { - unifiedMessage = (Term) messageConstraint; + unifiedMessage = messageConstraint; } for (ChannelMember leafMember: toResolve) { if (channel.getInputChannelMembers().contains(leafMember)) { @@ -248,9 +329,9 @@ messageConstraint = channel.calcMessageConstraintForReferenceMember(leafMember, null, resouceStateAccessor, null, substitutedPositionsInMessageFromChannels); } if (unifiedMessage == null) { - unifiedMessage = (Term) messageConstraint; + unifiedMessage = messageConstraint; } else { - unifiedMessage = (Term) unifiedMessage.unify(messageConstraint); + unifiedMessage = unifiedMessage.unify(messageConstraint); if (unifiedMessage == null) { throw new UnificationFailed(); } @@ -259,7 +340,9 @@ resolved.addAll(toResolve); toResolve.clear(); + // 2. Calculate message constraints from remaining members on the channel member dependency graph. for (;;) { + // Identify the channel members to resolve next. for (Map.Entry> dependEnt: dependency.entrySet()) { ChannelMember dependingMem = dependEnt.getKey(); Set dependedMems = dependEnt.getValue(); @@ -270,27 +353,22 @@ if (toResolve.size() == 0) break; for (ChannelMember dependingMem: toResolve) { // Fill the path parameters of the resource path of a depending channel member. - Set dependingVarPosInMessage = new HashSet<>(); - ResourcePath filledResPath = channel.fillOutsideResourcePath(dependingMem.getResource(), unifiedMessage, dependingMem.getStateTransition().getMessageExpression(), dependingVarPosInMessage); - ResourcePath unfilledResPath = dependingMem.getResource(); - for (int i = 0; i < unfilledResPath.getPathParamsAndConstraints().size(); i++) { - Expression var = unfilledResPath.getPathParamsAndConstraints().get(i).getKey(); - Expression val = filledResPath.getPathParamsAndConstraints().get(i).getKey(); - Expression constraint = unfilledResPath.getPathParamsAndConstraints().get(i).getValue(); - if (constraint != null && !constraint.equals(val)) { - // The value of the path parameter does not satisfy the constraint defined for the parameter. - return null; // Not to fire this event. - } - boolean isSelector = false; - for (Selector sel: channel.getAllSelectors()) { - if (sel.getExpression().equals(var)) { - isSelector = true; - break; + if (doesUpdateDependingParameters) { + Set dependingVarPosInMessage = new HashSet<>(); + ResourcePath filledResPath = channel.fillOutsideResourcePath(dependingMem.getResource(), unifiedMessage, dependingMem.getStateTransition().getMessageExpression(), dependingVarPosInMessage); + ResourcePath unfilledResPath = dependingMem.getResource(); + for (int i = 0; i < unfilledResPath.getPathParamsAndConstraints().size(); i++) { + Expression var = unfilledResPath.getPathParamsAndConstraints().get(i).getKey(); + Expression val = filledResPath.getPathParamsAndConstraints().get(i).getKey(); + Expression constraint = unfilledResPath.getPathParamsAndConstraints().get(i).getValue(); + if (constraint != null && !constraint.equals(val)) { + // The value of the path parameter does not satisfy the constraint defined for the parameter. + return null; // Not to fire this event. } - } - if (!isSelector) { - // Update a depending channel parameter - updateDependingParameter(var, val); + if (!channel.getAllSelectorVariables().contains(var)) { + // Update a depending channel parameter + updateDependingParameter(var, val); + } } } @@ -303,9 +381,9 @@ messageConstraint = channel.calcMessageConstraintForReferenceMember(dependingMem, null, resouceStateAccessor, null, substitutedPositionsInMessageFromChannels); } if (unifiedMessage == null) { - unifiedMessage = (Term) messageConstraint; + unifiedMessage = messageConstraint; } else { - unifiedMessage = (Term) unifiedMessage.unify(messageConstraint); + unifiedMessage = unifiedMessage.unify(messageConstraint); if (unifiedMessage == null) { throw new UnificationFailed(); } @@ -314,11 +392,98 @@ resolved.addAll(toResolve); toResolve.clear(); } - return unifiedMessage; - } catch (ResolvingMultipleDefinitionIsFutureWork | InvalidMessage | UnificationFailed e) { - e.printStackTrace(); + // For the channel members that are depended by and depend on no other member. + for (ChannelMember remainingMem: channel.getChannelMembers()) { + if (!resolved.contains(remainingMem)) { + resolved.add(remainingMem); + // Calculate message constraint + messageConstraint = null; + if (channel.getInputChannelMembers().contains(remainingMem)) { + // Calculate message constraint from an input state transition + messageConstraint = channel.calcMessageConstraintForInputMember(remainingMem, null, resouceStateAccessor, null, substitutedPositionsInMessageFromChannels); + } else if (channel.getReferenceChannelMembers().contains(remainingMem)) { + // Calculate message constraint from a reference state transition + messageConstraint = channel.calcMessageConstraintForReferenceMember(remainingMem, null, resouceStateAccessor, null, substitutedPositionsInMessageFromChannels); + } + if (messageConstraint != null) { + if (unifiedMessage == null) { + unifiedMessage = messageConstraint; + } else { + unifiedMessage = unifiedMessage.unify(messageConstraint); + if (unifiedMessage == null) { + throw new UnificationFailed(); + } + } + } + } + } } - return null; + if (inputResource == null) return unifiedMessage; + + // 3. Propagate parent event message to collect child events and calculate message constraints from child channels. + Resource baseResource = inputResource; + while (baseResource.getResourceHierarchy().getNumParameters() == 0) { + if (baseResource.getParent() == null) break; + baseResource = baseResource.getParent(); + } + Expression parentEventMessage = (Expression) unifiedMessage.clone(); + for (Channel childChannel: channel.getChildren()) { + // Search the deepest input or reference side resource path in each child channel that matches the channel parameters. + ChannelMember inOrRef = null; + Set channelMembers = new HashSet<>(((DataTransferChannel) childChannel).getInputChannelMembers()); + channelMembers.addAll(((DataTransferChannel) childChannel).getReferenceChannelMembers()); + for (ChannelMember cm: channelMembers) { + if (!cm.isOutside()) { + ResourcePath resPath = cm.getResource(); + if (resPath.getPathParams().containsAll(childChannel.getAllSelectorVariables())) { + inOrRef = cm; + break; + } + } + } + if (inOrRef != null) { + // Collect events for all resources under this event's input resource that matches the deepest input side resource path. + for (Resource res: baseResource.getDescendants(inOrRef.getResource().getResourceHierarchy())) { + Event childEvent = new Event((DataTransferChannel) childChannel, inOrRef.getResource(), res); + childEvent.setMessage(parentEventMessage); + messageConstraint = childEvent.constructMessageAndDesdendantEvents(resourceStateValueProvider, substitutedPositionsInMessageFromChannels, true); + if (messageConstraint != null) { + childEvent.setMessage(messageConstraint); + if (unifiedMessage == null) { + unifiedMessage = messageConstraint; + } else { + unifiedMessage = unifiedMessage.unify(messageConstraint); + if (unifiedMessage == null) { + throw new UnificationFailed(); + } + } + childEvents.add(childEvent); + } + } + } else { + // Search the deepest output side resource path in each child channel that matches the channel parameters. + ChannelMember out = null; + for (ChannelMember cm: ((DataTransferChannel) childChannel).getOutputChannelMembers()) { + if (!cm.isOutside()) { + ResourcePath resPath = cm.getResource(); + if (resPath.getPathParams().containsAll(childChannel.getAllSelectorVariables())) { + out = cm; + break; + } + } + } + if (out != null) { + // Collect events for all resources under this event's input resource that matches the deepest output side resource path. + for (Resource res: baseResource.getDescendants(out.getResource().getResourceHierarchy())) { + Event childEvent = new Event((DataTransferChannel) childChannel, parentEventMessage, out.getResource(), res); + childEvent.constructMessageAndDesdendantEvents(resourceStateValueProvider, substitutedPositionsInMessageFromChannels, true); + childEvents.add(childEvent); + } + } + } + } + + return unifiedMessage; } public void updateDependingParameter(Expression variable, Expression value) { @@ -337,33 +502,37 @@ return outputResources; } - public Set getSuccessors() { - return succEvents; - } - - public void addSuccessor(Event succEvt) { - succEvents.add(succEvt); - } - public ResourceIdentifier getResourceIdentifier(ResourcePath resPath) { ResourceIdentifier resId = ResourceIdentifier.createFrom(resPath); for (Map.Entry chParamEnt: channelSelectorAndValues) { Selector sel = chParamEnt.getKey(); - Map inputPathParamEnt = channelSelectorToInputResourcePathParam.get(sel); - if (inputPathParamEnt != null) { - Integer paramIdx = inputPathParamEnt.get(resPath); - if (paramIdx != null) { - resId.setPathParam(paramIdx, chParamEnt.getValue()); + Map>> inputPathToIdxAndPos = channelSelectorToInputOrReferenceResourcePathParam.get(sel); + if (inputPathToIdxAndPos != null) { + Map.Entry> pathParamEnt = inputPathToIdxAndPos.get(resPath); + if (pathParamEnt != null) { + Integer paramIdx = pathParamEnt.getKey(); + if (paramIdx != null) { + Expression pathParamExp = resId.getPathParams().get(paramIdx); + if (pathParamExp instanceof Variable) { + resId.setPathParam(paramIdx, chParamEnt.getValue()); + } + } } } } for (Map.Entry chParamEnt: channelSelectorAndValues) { Selector sel = chParamEnt.getKey(); - Map outputPathParamEnt = channelSelectorToOutputResourcePathParam.get(sel); - if (outputPathParamEnt != null) { - Integer paramIdx = outputPathParamEnt.get(resPath); - if (paramIdx != null) { - resId.setPathParam(paramIdx, chParamEnt.getValue()); + Map>> outputPathToIdxAndPos = channelSelectorToOutputResourcePathParam.get(sel); + if (outputPathToIdxAndPos != null) { + Map.Entry> pathParamEnt = outputPathToIdxAndPos.get(resPath); + if (pathParamEnt != null) { + Integer paramIdx = pathParamEnt.getKey(); + if (paramIdx != null) { + Expression pathParamExp = resId.getPathParams().get(paramIdx); + if (pathParamExp instanceof Variable) { + resId.setPathParam(paramIdx, chParamEnt.getValue()); + } + } } } } @@ -373,6 +542,40 @@ resId.setPathParam(paramIdx, (Constant) dependingParameters.get(var)); } } + for (Map.Entry chParamEnt: channelSelectorAndValues) { + Selector sel = chParamEnt.getKey(); + Map>> inputPathToIdxAndPos = channelSelectorToInputOrReferenceResourcePathParam.get(sel); + if (inputPathToIdxAndPos != null) { + Map.Entry> pathParamEnt = inputPathToIdxAndPos.get(resPath); + if (pathParamEnt != null) { + Integer paramIdx = pathParamEnt.getKey(); + if (paramIdx != null) { + Expression pathParamExp = resId.getPathParams().get(paramIdx); + if (pathParamExp instanceof Term && sel.getExpression() instanceof Variable) { + pathParamExp = ((Term) pathParamExp).substitute((Variable) sel.getExpression(), chParamEnt.getValue()); + resId.setPathParam(paramIdx, ((Term) pathParamExp).reduce()); + } + } + } + } + } + for (Map.Entry chParamEnt: channelSelectorAndValues) { + Selector sel = chParamEnt.getKey(); + Map>> outputPathToIdxAndPos = channelSelectorToOutputResourcePathParam.get(sel); + if (outputPathToIdxAndPos != null) { + Map.Entry> pathParamEnt = outputPathToIdxAndPos.get(resPath); + if (pathParamEnt != null) { + Integer paramIdx = pathParamEnt.getKey(); + if (paramIdx != null) { + Expression pathParamExp = resId.getPathParams().get(paramIdx); + if (pathParamExp instanceof Term && sel.getExpression() instanceof Variable) { + pathParamExp = ((Term) pathParamExp).substitute((Variable) sel.getExpression(), chParamEnt.getValue()); + resId.setPathParam(paramIdx, ((Term) pathParamExp).reduce()); + } + } + } + } + } return resId; } @@ -380,10 +583,16 @@ ResourceIdentifier resId = ResourceIdentifier.createFrom(inputResPath); for (Map.Entry chParamEnt: channelSelectorAndValues) { Selector sel = chParamEnt.getKey(); - if (channelSelectorToInputResourcePathParam.get(sel) != null) { - Integer paramIdx = channelSelectorToInputResourcePathParam.get(sel).get(inputResPath); - if (paramIdx != null) { - resId.setPathParam(paramIdx, chParamEnt.getValue()); + if (channelSelectorToInputOrReferenceResourcePathParam.get(sel) != null) { + Map.Entry> pathParamEnt = channelSelectorToInputOrReferenceResourcePathParam.get(sel).get(inputResPath); + if (pathParamEnt != null) { + Integer paramIdx = pathParamEnt.getKey(); + if (paramIdx != null) { + Expression pathParamExp = resId.getPathParams().get(paramIdx); + if (pathParamExp instanceof Variable) { + resId.setPathParam(paramIdx, chParamEnt.getValue()); + } + } } } } @@ -393,6 +602,22 @@ resId.setPathParam(paramIdx, (Constant) dependingParameters.get(var)); } } + for (Map.Entry chParamEnt: channelSelectorAndValues) { + Selector sel = chParamEnt.getKey(); + if (channelSelectorToInputOrReferenceResourcePathParam.get(sel) != null) { + Map.Entry> pathParamEnt = channelSelectorToInputOrReferenceResourcePathParam.get(sel).get(inputResPath); + if (pathParamEnt != null) { + Integer paramIdx = pathParamEnt.getKey(); + if (paramIdx != null) { + Expression pathParamExp = resId.getPathParams().get(paramIdx); + if (pathParamExp instanceof Term && sel.getExpression() instanceof Variable) { + pathParamExp = ((Term) pathParamExp).substitute((Variable) sel.getExpression(), chParamEnt.getValue()); + resId.setPathParam(paramIdx, ((Term) pathParamExp).reduce()); + } + } + } + } + } return resId; } @@ -401,16 +626,38 @@ for (Map.Entry chParamEnt: channelSelectorAndValues) { Selector sel = chParamEnt.getKey(); if (channelSelectorToOutputResourcePathParam.get(sel) != null) { - Integer paramIdx = channelSelectorToOutputResourcePathParam.get(sel).get(outputResPath); - if (paramIdx != null) { - resId.setPathParam(paramIdx, chParamEnt.getValue()); + Map.Entry> pathParamEnt = channelSelectorToOutputResourcePathParam.get(sel).get(outputResPath); + if (pathParamEnt != null) { + Integer paramIdx = pathParamEnt.getKey(); + if (paramIdx != null) { + Expression pathParamExp = resId.getPathParams().get(paramIdx); + if (pathParamExp instanceof Variable) { + resId.setPathParam(paramIdx, chParamEnt.getValue()); + } + } } } } for (Expression var: dependingParameters.keySet()) { int paramIdx = resId.getPathParams().indexOf(var); if (paramIdx >= 0) { - resId.setPathParam(paramIdx, (Constant) dependingParameters.get(var)); + resId.setPathParam(paramIdx, dependingParameters.get(var)); + } + } + for (Map.Entry chParamEnt: channelSelectorAndValues) { + Selector sel = chParamEnt.getKey(); + if (channelSelectorToOutputResourcePathParam.get(sel) != null) { + Map.Entry> pathParamEnt = channelSelectorToOutputResourcePathParam.get(sel).get(outputResPath); + if (pathParamEnt != null) { + Integer paramIdx = pathParamEnt.getKey(); + if (paramIdx != null) { + Expression pathParamExp = resId.getPathParams().get(paramIdx); + if (pathParamExp instanceof Term && sel.getExpression() instanceof Variable) { + pathParamExp = ((Term) pathParamExp).substitute((Variable) sel.getExpression(), chParamEnt.getValue()); + resId.setPathParam(paramIdx, ((Term) pathParamExp).reduce()); + } + } + } } } return resId; diff --git a/AlgebraicDataflowArchitectureModel/src/simulator/Resource.java b/AlgebraicDataflowArchitectureModel/src/simulator/Resource.java index ac2c94b..8cd943f 100644 --- a/AlgebraicDataflowArchitectureModel/src/simulator/Resource.java +++ b/AlgebraicDataflowArchitectureModel/src/simulator/Resource.java @@ -1,8 +1,10 @@ package simulator; import java.util.Collection; +import java.util.HashSet; import java.util.LinkedHashMap; import java.util.Map; +import java.util.Set; import models.algebra.Constant; import models.algebra.Expression; @@ -11,6 +13,11 @@ import models.dataConstraintModel.ResourceHierarchy; import simulator.states.*; +/** + * A runtime instance of a resource + * @author Nitta + * + */ public class Resource { private Resource parent = null; private Map children = null; @@ -172,6 +179,20 @@ return children; } + public Set getDescendants(ResourceHierarchy res) { + if (this.getResourceHierarchy().equals(res)) { + Set descendants = new HashSet<>(); + descendants.add(this); + return descendants; + } + if (!res.toString().startsWith(this.getResourceHierarchy().toString())) return new HashSet<>(); + Set descendants = new HashSet<>(); + for (Resource child: getChildren()) { + descendants.addAll(child.getDescendants(res)); + } + return descendants; + } + public Resource getDescendant(ResourceIdentifier resId) { if (this.getResourceIdentifier().equals(resId)) return this; if (!resId.startsWith(this.getResourceIdentifier())) return null; diff --git a/AlgebraicDataflowArchitectureModel/src/simulator/ResourceIdentifier.java b/AlgebraicDataflowArchitectureModel/src/simulator/ResourceIdentifier.java index 8987ee0..13b2c92 100644 --- a/AlgebraicDataflowArchitectureModel/src/simulator/ResourceIdentifier.java +++ b/AlgebraicDataflowArchitectureModel/src/simulator/ResourceIdentifier.java @@ -25,7 +25,7 @@ super(parentResId, exp, resourceHierarchy); } - public void setPathParam(int paramIdx, Constant param) { + public void setPathParam(int paramIdx, Expression param) { if (paramIdx < pathParams.size()) { pathParams.set(paramIdx, new AbstractMap.SimpleEntry<>(param, null)); if (parent != null) { @@ -130,7 +130,7 @@ return new ResourceIdentifier(parent, resPath.getLeafResourceName(), res); } } else { - return new ResourceIdentifier(parent, resPath.getLastParam(), res); + return new ResourceIdentifier(parent, (Expression) resPath.getLastParam().clone(), res); } } diff --git a/AlgebraicDataflowArchitectureModel/src/simulator/Simulator.java b/AlgebraicDataflowArchitectureModel/src/simulator/Simulator.java index a2df91d..2a93a6e 100644 --- a/AlgebraicDataflowArchitectureModel/src/simulator/Simulator.java +++ b/AlgebraicDataflowArchitectureModel/src/simulator/Simulator.java @@ -1,6 +1,7 @@ package simulator; import java.util.AbstractMap; +import java.util.AbstractMap.SimpleEntry; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; @@ -30,6 +31,11 @@ import simulator.interfaces.INativeInitializer; import simulator.interfaces.INativeReceiver; +/** + * Simulator to run a model + * @author Nitta + * + */ public class Simulator { private DataTransferModel model; private SystemState curState; @@ -95,7 +101,7 @@ public SystemState transition(Event inputEvent) throws ParameterizedIdentifierIsFutureWork, ResolvingMultipleDefinitionIsFutureWork, InvalidMessage, UnificationFailed, ValueUndefined { SystemState nextSystemState = new SystemState(curState); - inputEvent.updateDependingParameters(new ResourceStateValueProvider(curState, nextSystemState)); + inputEvent.constructMessageAndDescendantEvents(new ResourceStateValueProvider(curState, nextSystemState), true); nextSystemState.addEvent(inputEvent); fireEvent(inputEvent, curState, nextSystemState); @@ -192,8 +198,14 @@ return res.getState().getValue(); } }; - - DataTransferChannel channel = event.getChannel(); + + // First, fire the all child events. + for (Event childEvent: event.getChildren()) { + fireEvent(childEvent, curSystemState, nextSystemState); + } + + // Fire this event. + DataTransferChannel channel = event.getChannel(); if (channel.getOutputResources().size() > 0) { // For each output resource, calculate the next state. for (ChannelMember out: channel.getOutputChannelMembers()) { @@ -201,7 +213,7 @@ Expression nextResState = null; outTarget[0] = out; outResVar[0] = new Variable(channel.getChannelName() + "$" + out.getResource().toString() + "$this"); // A special variable to represent the current state of each output resource. - if (!event.isInput() || event.getMessage() instanceof Variable) { + if (event.getMessage() instanceof Variable) { nextResState = channel.deriveUpdateExpressionOf(out, resouceStateAccessor).getKey(); } else { nextResState = channel.deriveUpdateExpressionOf(out, (Term) event.getMessage(), resouceStateAccessor); @@ -252,13 +264,16 @@ } } - private Set getNextEvents(ResourceIdentifier inResId, SystemState curSystemState, SystemState nextSystemState) - throws ParameterizedIdentifierIsFutureWork, ResolvingMultipleDefinitionIsFutureWork, InvalidMessage, UnificationFailed, ValueUndefined { - Set nextEvents = new HashSet<>(); + private Set getNextEvents(ResourceIdentifier inResId, SystemState curSystemState, SystemState nextSystemState) { IResourceStateValueProvider resourceStateValueProvider = new ResourceStateValueProvider(curSystemState, nextSystemState); - for (Map.Entry chEntry: nextSystemState.getChannelStates().entrySet()) { - DataTransferChannel channel = chEntry.getKey(); - ChannelState nextChState = chEntry.getValue(); + Set nextEvents = new HashSet<>(); + for (Channel ch: model.getChannels()) { + DataTransferChannel channel = (DataTransferChannel) ch; + ChannelState nextChannelState = nextSystemState.getChannelState(channel); + if (nextChannelState == null) { + nextChannelState = new ChannelState(channel); + nextSystemState.updateChannelState(channel, nextChannelState); + } Map> dependency = channel.getMemberDependency(); Map> invDependency = new HashMap<>(); for (ChannelMember dependingMem: dependency.keySet()) { @@ -277,18 +292,16 @@ boolean isInputResourceDepended = false; for (ChannelMember dependedMem: invDependency.keySet()) { if (inResPath == dependedMem.getResource()) { - // If some depending resources are to be updated by the update of an depended input resource. + // 1) If some depending resources are to be updated by the update of an 'depended' input resource. if (doesSatifsyPathConstraints(inResPath, inResId)) { Event nextEvent = new Event(channel, inResPath, nextSystemState.getResource(inResId)); - Expression message = nextEvent.updateDependingParameters(resourceStateValueProvider); + Expression message = nextEvent.constructMessageAndDescendantEvents(resourceStateValueProvider, true); if (message != null) { - if (nextChState == null) { - nextChState = new ChannelState(channel); - nextSystemState.updateChannelState(channel, nextChState); - } + nextEvent.setMessage(message); + nextSystemState.updateChannelState(channel, nextChannelState); List channelSelValues = nextEvent.getChannelSelectorValues(); for (Map.Entry paramEnt: nextEvent.getDependingParameters().entrySet()) { - nextChState.addDependingParamAndValue(channelSelValues, paramEnt.getKey(), paramEnt.getValue()); + nextChannelState.addDependingParamAndValue(channelSelValues, paramEnt.getKey(), paramEnt.getValue()); } nextEvents.add(nextEvent); } @@ -305,63 +318,58 @@ if (!isInputResourceDepended && !isInputResourceDepending) { if (doesSatifsyPathConstraints(inResPath, inResId)) { Event nextEvent = new Event(channel, inResPath, nextSystemState.getResource(inResId)); - Expression message = nextEvent.updateDependingParameters(resourceStateValueProvider); + Expression message = nextEvent.constructMessageAndDescendantEvents(resourceStateValueProvider, true); if (message != null) { nextEvent.setMessage(message); nextEvents.add(nextEvent); } } } - if (nextChState != null) { - for (ChannelMember dependingMem: dependency.keySet()) { - if (inResPath == dependingMem.getResource()) { - // If a depending resource is directly updated. - ResourcePath filledResPath = inResId; - ResourcePath unfilledResPath = inResPath; - // Extract the values of path parameters from the updated resource identifier. - Map selectorVarToVal = new HashMap<>(); - Map dependingVarToVal = new HashMap<>(); - boolean doesSatisfyConstraint = true; - for (int i = 0; i < unfilledResPath.getPathParamsAndConstraints().size(); i++) { - Expression var = unfilledResPath.getPathParamsAndConstraints().get(i).getKey(); - Expression val = filledResPath.getPathParamsAndConstraints().get(i).getKey(); - Expression constraint = unfilledResPath.getPathParamsAndConstraints().get(i).getValue(); - if (constraint != null && !constraint.equals(val)) { - // The value of the path parameter does not satisfy the constraint defined for the parameter. - doesSatisfyConstraint = false; - break; - } - boolean isSelector = false; - for (Selector sel: channel.getAllSelectors()) { - if (sel.getExpression().equals(var)) { - isSelector = true; - break; - } - } - if (isSelector) { - selectorVarToVal.put(var, val); - } else { - dependingVarToVal.put(var, val); - } + for (ChannelMember dependingMem: dependency.keySet()) { + if (inResPath == dependingMem.getResource()) { + // 2) If a 'depending' resource is directly updated. + ResourcePath filledResPath = inResId; + ResourcePath unfilledResPath = inResPath; + // Extract the values of path parameters from the updated resource identifier. + Map selectorVarToVal = new HashMap<>(); + Map dependingVarToVal = new HashMap<>(); + boolean doesSatisfyConstraint = true; + for (int i = 0; i < unfilledResPath.getPathParamsAndConstraints().size(); i++) { + Expression var = unfilledResPath.getPathParamsAndConstraints().get(i).getKey(); + Expression val = filledResPath.getPathParamsAndConstraints().get(i).getKey(); + Expression constraint = unfilledResPath.getPathParamsAndConstraints().get(i).getValue(); + if (constraint != null && !constraint.equals(val)) { + // The value of the path parameter does not satisfy the constraint defined for the parameter. + doesSatisfyConstraint = false; + break; } - if (doesSatisfyConstraint) { - List> dependedChannelSelectorValues = nextChState.getDependedChannelSelectorValues(dependingVarToVal); - if (dependedChannelSelectorValues != null) { - for (List channelSelectorValues: dependedChannelSelectorValues) { - // Guess every tuple of channel selector values that may affects the updated resource. - boolean doesMatch = true; - for (Expression var: selectorVarToVal.keySet()) { - for (int i = 0; i < channel.getAllSelectors().size(); i++) { - if (channel.getAllSelectors().get(i).getExpression().equals(var)) { - if (!channelSelectorValues.get(i).equals(selectorVarToVal.get(var))) { - // If the value of a selector in the updated resource path does not matches a guessed channel selector value. - doesMatch = false; - } + if (channel.getAllSelectorVariables().contains(var)) { + selectorVarToVal.put(var, val); + } else { + dependingVarToVal.put(var, val); + } + } + if (doesSatisfyConstraint) { + List> dependedChannelSelectorValues = nextChannelState.getDependedChannelSelectorValues(dependingVarToVal); + if (dependedChannelSelectorValues != null) { + for (List channelSelectorValues: dependedChannelSelectorValues) { + // Guess every tuple of channel selector values that may affects the updated resource. + boolean doesMatch = true; + for (Expression var: selectorVarToVal.keySet()) { + for (int i = 0; i < channel.getAllSelectors().size(); i++) { + if (channel.getAllSelectors().get(i).getExpression().equals(var)) { + if (!channelSelectorValues.get(i).equals(selectorVarToVal.get(var))) { + // If the value of a selector in the updated resource path does not matches a guessed channel selector value. + doesMatch = false; } } } - if (doesMatch) { - Event nextEvent = new Event(channel, inResPath, nextSystemState.getResource(inResId), channelSelectorValues, dependingVarToVal); + } + if (doesMatch) { + Event nextEvent = new Event(channel, inResPath, nextSystemState.getResource(inResId), channelSelectorValues, dependingVarToVal); + Expression message = nextEvent.constructMessageAndDescendantEvents(resourceStateValueProvider, false); + if (message != null) { + nextEvent.setMessage(message); nextEvents.add(nextEvent); } } @@ -372,10 +380,182 @@ } } } + // 3) If a resource in a descendant channel is directly updated. + ResourcePath inResPath = null; + for (ResourcePath path: channel.getInputResources()) { + if (path.getPathParams().containsAll(channel.getAllSelectorVariables())) { + inResPath = path; + } + } + if (inResPath != null) { + for (Map.Entry, Event> childEventEnt: collectDescendantEvents(channel, channel, inResId, nextSystemState, resourceStateValueProvider)) { + Event childEvent = childEventEnt.getValue(); + nextEvents.add(childEvent); + } + } } return nextEvents; } + private List, Event>> collectDescendantEvents(DataTransferChannel rootChannel, DataTransferChannel channel, ResourceIdentifier inResId, + SystemState nextSystemState, IResourceStateValueProvider resourceStateValueProvider) { + List, Event>> childEvents = new ArrayList<>(); + ChannelState nextChannelState = nextSystemState.getChannelState(rootChannel); + for (Channel childCh: channel.getChildren()) { + DataTransferChannel childChannel = (DataTransferChannel) childCh; + Map> dependency = childChannel.getMemberDependency(); + Map> invDependency = new HashMap<>(); + for (ChannelMember dependingMem: dependency.keySet()) { + for (ChannelMember dependedMem: dependency.get(dependingMem)) { + Set dependings = invDependency.get(dependedMem); + if (dependings == null) { + dependings = new HashSet<>(); + invDependency.put(dependedMem, dependings); + } + dependings.add(dependingMem); + } + } + for (ResourcePath childInResPath: childChannel.getInputResources()) { + if (inResId.isInstanceOf(childInResPath)) { + boolean isInputResourceDepended = false; + for (ChannelMember dependedMem: invDependency.keySet()) { + if (childInResPath == dependedMem.getResource()) { + // 1) If some depending resources are to be updated by the update of an 'depended' input resource. + if (doesSatifsyPathConstraints(childInResPath, inResId)) { + Event childEvent = new Event(childChannel, childInResPath, nextSystemState.getResource(inResId)); + Expression message = childEvent.constructMessageAndDescendantEvents(resourceStateValueProvider, true); + if (message != null) { + childEvent.setMessage(message); + List childChannelSelValues = childEvent.getChannelSelectorValues(); + for (Map.Entry paramEnt: childEvent.getDependingParameters().entrySet()) { + nextChannelState.addDependingParamAndValue(childChannelSelValues, paramEnt.getKey(), paramEnt.getValue()); + } + if (childChannelSelValues.size() >= childChannel.getSelectors().size()) { + List channelSelectorValues = new ArrayList<>(childChannelSelValues); + for (int i = 0; i < childChannel.getSelectors().size(); i++) { + channelSelectorValues.remove(childChannelSelValues.size() - 1 - i); + } + childEvents.add(new AbstractMap.SimpleEntry<>(channelSelectorValues, childEvent)); + } + } + } + isInputResourceDepended = true; + } + } + boolean isInputResourceDepending = false; + for (ChannelMember dependingMem: dependency.keySet()) { + if (childInResPath == dependingMem.getResource()) { + isInputResourceDepending = true; + } + } + if (!isInputResourceDepended && !isInputResourceDepending) { + if (doesSatifsyPathConstraints(childInResPath, inResId)) { + Event childEvent = new Event(childChannel, childInResPath, nextSystemState.getResource(inResId)); + Expression message = childEvent.constructMessageAndDescendantEvents(resourceStateValueProvider, true); + if (message != null) { + childEvent.setMessage(message); + List childChannelSelValues = childEvent.getChannelSelectorValues(); + for (Map.Entry paramEnt: childEvent.getDependingParameters().entrySet()) { + nextChannelState.addDependingParamAndValue(childChannelSelValues, paramEnt.getKey(), paramEnt.getValue()); + } + if (childChannelSelValues.size() >= childChannel.getSelectors().size()) { + List channelSelectorValues = new ArrayList<>(childChannelSelValues); + for (int i = 0; i < childChannel.getSelectors().size(); i++) { + channelSelectorValues.remove(childChannelSelValues.size() - 1 - i); + } + childEvents.add(new AbstractMap.SimpleEntry<>(channelSelectorValues, childEvent)); + } + } + } + } + for (ChannelMember dependingMem: dependency.keySet()) { + if (childInResPath == dependingMem.getResource()) { + // 2) If a 'depending' resource is directly updated. + ResourcePath filledResPath = inResId; + ResourcePath unfilledResPath = childInResPath; + // Extract the values of path parameters from the updated resource identifier. + Map selectorVarToVal = new HashMap<>(); + Map dependingVarToVal = new HashMap<>(); + boolean doesSatisfyConstraint = true; + for (int i = 0; i < unfilledResPath.getPathParamsAndConstraints().size(); i++) { + Expression var = unfilledResPath.getPathParamsAndConstraints().get(i).getKey(); + Expression val = filledResPath.getPathParamsAndConstraints().get(i).getKey(); + Expression constraint = unfilledResPath.getPathParamsAndConstraints().get(i).getValue(); + if (constraint != null && !constraint.equals(val)) { + // The value of the path parameter does not satisfy the constraint defined for the parameter. + doesSatisfyConstraint = false; + break; + } + if (channel.getAllSelectorVariables().contains(var)) { + selectorVarToVal.put(var, val); + } else { + dependingVarToVal.put(var, val); + } + } + if (doesSatisfyConstraint) { + List> dependedChannelSelectorValues = nextChannelState.getDependedChannelSelectorValues(dependingVarToVal); + if (dependedChannelSelectorValues != null) { + for (List childChannelSelectorValues: dependedChannelSelectorValues) { + // Guess every tuple of channel selector values that may affects the updated resource. + boolean doesMatch = true; + for (Expression var: selectorVarToVal.keySet()) { + for (int i = 0; i < channel.getAllSelectors().size(); i++) { + if (channel.getAllSelectors().get(i).getExpression().equals(var)) { + if (!childChannelSelectorValues.get(i).equals(selectorVarToVal.get(var))) { + // If the value of a selector in the updated resource path does not matches a guessed channel selector value. + doesMatch = false; + } + } + } + } + if (doesMatch) { + Event childEvent = new Event(childChannel, childInResPath, nextSystemState.getResource(inResId), childChannelSelectorValues, dependingVarToVal); + Expression message = childEvent.constructMessageAndDescendantEvents(resourceStateValueProvider, false); + if (message != null) { + childEvent.setMessage(message); + if (childChannelSelectorValues.size() >= childChannel.getSelectors().size()) { + List channelSelectorValues = new ArrayList<>(childChannelSelectorValues); + for (int i = 0; i < childChannel.getSelectors().size(); i++) { + channelSelectorValues.remove(childChannelSelectorValues.size() - 1 - i); + } + childEvents.add(new AbstractMap.SimpleEntry<>(channelSelectorValues, childEvent)); + } + } + } + } + } + } + } + } + } + } + // 3) If a resource in a descendant channel is directly updated. + childEvents.addAll(collectDescendantEvents(rootChannel, childChannel, inResId, nextSystemState, resourceStateValueProvider)); + } + List, Event>> events = new ArrayList<>(); + ResourcePath inResPath = null; + for (ResourcePath path: channel.getInputResources()) { + if (path.getPathParams().containsAll(channel.getAllSelectorVariables())) { + inResPath = path; + } + } + for (Map.Entry, Event> childEventEnt: childEvents) { + List channelSelectorValues = childEventEnt.getKey(); + Event childEvent = childEventEnt.getValue(); + Map dependingVarToVal = nextChannelState.getDependingParamAndValues(channelSelectorValues); + Event event = new Event((DataTransferChannel) channel, inResPath, nextSystemState.getResource(inResId), channelSelectorValues, dependingVarToVal); + event.addChild(childEvent); + if (channelSelectorValues.size() >= channel.getSelectors().size()) { + List parentChannelSelectorValues = new ArrayList<>(channelSelectorValues); + for (int i = 0; i < channel.getSelectors().size(); i++) { + parentChannelSelectorValues.remove(channelSelectorValues.size() - 1 - i); + } + events.add(new AbstractMap.SimpleEntry<>(parentChannelSelectorValues, event)); + } + } + return events; + } + private boolean doesSatifsyPathConstraints(ResourcePath resPath, ResourceIdentifier resId) { for (int i = 0; i < resPath.getPathParamsAndConstraints().size(); i++) { Expression val = resId.getPathParamsAndConstraints().get(i).getKey(); diff --git a/AlgebraicDataflowArchitectureModel/src/simulator/SystemState.java b/AlgebraicDataflowArchitectureModel/src/simulator/SystemState.java index e078ccb..1b19ac6 100644 --- a/AlgebraicDataflowArchitectureModel/src/simulator/SystemState.java +++ b/AlgebraicDataflowArchitectureModel/src/simulator/SystemState.java @@ -26,6 +26,11 @@ import simulator.states.PrimitiveResourceState; import simulator.states.ResourceState; +/** + * The whole state of a running model + * @author Nitta + * + */ public class SystemState { private Set rootResources = new HashSet<>(); private Map channelStates = new HashMap<>(); diff --git a/AlgebraicDataflowArchitectureModel/src/simulator/states/PrimitiveResourceState.java b/AlgebraicDataflowArchitectureModel/src/simulator/states/PrimitiveResourceState.java index adfb7f3..19db331 100644 --- a/AlgebraicDataflowArchitectureModel/src/simulator/states/PrimitiveResourceState.java +++ b/AlgebraicDataflowArchitectureModel/src/simulator/states/PrimitiveResourceState.java @@ -26,6 +26,7 @@ } public Object clone() { - return this; + if (value == null) return new PrimitiveResourceState(null); + return new PrimitiveResourceState((Constant) value.clone()); } } diff --git a/AlgebraicDataflowArchitectureModel/src/simulator/states/State.java b/AlgebraicDataflowArchitectureModel/src/simulator/states/State.java index 2dfa5c0..00883d9 100644 --- a/AlgebraicDataflowArchitectureModel/src/simulator/states/State.java +++ b/AlgebraicDataflowArchitectureModel/src/simulator/states/State.java @@ -2,6 +2,11 @@ import models.algebra.Expression; +/** + * A state of a resource + * @author Nitta + * + */ abstract public class State implements Cloneable { abstract public Expression getValue(); abstract public Object clone();