/// <summary> /// /// </summary> /// <param name="scfg"></param> /// <param name="aprot">If called for an agent activity - implemented protocol, otherwise null</param> /// <returns></returns> public bool Validate(SourceContext defaultContext) { HashSet <int> exclude = new HashSet <int>(); foreach (GNode g in scfg.allNodes) { g.visited = false; } if (aprot != null && !aprot.ErrorReported) { aprot.syntax.validate(); aprot.syntax.convert(); if (aprot.syntax.table != null) { ptotable[0] = new Rules(aprot.syntax.table.GetServerEBNF(), aprot.syntax.testFunction.tests, "(" + aprot.Name + ") anonymous client"); scfg.entry.AddStateFor(ptotable[0].id, 0); //Entry point } } Queue <GNode> visitNext = new Queue <GNode>(); visitNext.Enqueue(scfg.entry); GNode node = scfg.entry; while (visitNext.Count > 0) { node = visitNext.Dequeue(); node.visited = true; foreach (GNode next in node.successors) { bool needtocopy = true; if (next.astNode is ASSIGNMENT) { // Interested in p := new A; ASSIGNMENT nnode = next.astNode as ASSIGNMENT; if (nnode.right_part is NEW && nnode.right_part.type is ACTIVITY_TYPE) { if (nnode.receiver is INSTANCE) { int id = ((INSTANCE)nnode.receiver).entity.unique; ACTIVITY_TYPE acttype = nnode.right_part.type as ACTIVITY_TYPE; if (((ACTIVITY_DECL)(acttype.activity)).prototype is PROTOCOL_DECL) { if (!((ACTIVITY_DECL)(acttype.activity)).prototype.ErrorReported) { PROTOCOL_DECL eprot = ((ACTIVITY_DECL)(acttype.activity)).prototype as PROTOCOL_DECL; eprot.syntax.validate(); eprot.syntax.convert(); if (eprot.syntax.table != null) { ptotable[id] = new Rules(eprot.syntax.table.GetClientEBNF(), eprot.syntax.testFunction.tests, "(" + eprot.name + ")" + ((INSTANCE)nnode.receiver).Name); next.AddStateFor(ptotable[id].id, 0); node.ForwardAllStatesExceptOneTo(next, ptotable[id].id); needtocopy = false; } } } else { // Else it's ok. Do not trace this variable // Add to exclude set. All other cases will be treated with error: Not initialized dialog exclude.Add(id); } } else { if (!nnode.ErrorReported) { ERROR.ActivityVariableMustBeLocal(nnode.sourceContext); } nnode.ErrorReported = true; } } else if ((nnode.right_part is CALL) && (((CALL)nnode.right_part).callee is INSTANCE && (((CALL)nnode.right_part).type is ABSTRACT_ACTIVITY_TYPE || ((CALL)nnode.right_part).type is ACTIVITY_TYPE)) ) { int id = ((INSTANCE)((CALL)nnode.right_part).callee).entity.unique; if (!exclude.Contains(id)) { if (ptotable.ContainsKey(id)) { Rules rules = ptotable[id]; foreach (int protocolState in node.GetStatesFor(rules.id)) { int nextstate = protocolState; for (int i = 0; i < ((CALL)nnode.right_part).arguments.Length; i++) { EXPRESSION des = ((CALL)nnode.right_part).arguments[i]; int savestate = nextstate; if ((nextstate = ValidateDataTransfer(rules, nextstate, false, des, true)) < 0) { if (!next.astNode.ErrorReported && !rules.errorReported) { ERROR.ProtocolViolation(next.astNode.sourceContext, rules.ExpectedAtState(savestate, true)); next.astNode.ErrorReported = true; rules.errorReported = true; } } else if (nextstate == 0) // This was the last send/receive { nextstate = -1; } } { /* Process the receive */ EXPRESSION des = nnode.receiver; int savestate = nextstate; if ((nextstate = ValidateDataTransfer(rules, nextstate, true, des, false)) < 0) { if (!next.astNode.ErrorReported && !rules.errorReported) { ERROR.ProtocolViolation(next.astNode.sourceContext, rules.ExpectedAtState(savestate, true)); next.astNode.ErrorReported = true; rules.errorReported = true; } } else if (nextstate == 0) // This was the last send/receive { nextstate = -1; } } next.AddStateFor(rules.id, nextstate); node.ForwardAllStatesExceptOneTo(next, rules.id); needtocopy = false; } } else { ERROR.AcceptCalledForInvalidDialog(nnode.sourceContext); } } } } else if (next.astNode is ACCEPT) { ACCEPT anode = next.astNode as ACCEPT; if (ptotable.ContainsKey(0)) { Rules rules = ptotable[0]; foreach (int protocolState in node.GetStatesFor(rules.id)) { int nextstate = protocolState; for (int i = 0; i < anode.designators.Length; i++) { EXPRESSION des = anode.designators[i]; int savestate = nextstate; if ((nextstate = ValidateDataTransfer(rules, nextstate, false, des, false)) < 0) { if (!next.astNode.ErrorReported && !rules.errorReported) { ERROR.ProtocolViolation(next.astNode.sourceContext, rules.ExpectedAtState(savestate, false)); next.astNode.ErrorReported = true; rules.errorReported = true; } } else if (nextstate == 0) // This was the last send/receive { nextstate = -1; } } next.AddStateFor(rules.id, nextstate); node.ForwardAllStatesExceptOneTo(next, rules.id); needtocopy = false; } } } else if (next.astNode is REPLY) { REPLY rnode = next.astNode as REPLY; if (ptotable.ContainsKey(0)) { Rules rules = ptotable[0]; foreach (int protocolState in node.GetStatesFor(rules.id)) { int nextstate = protocolState; for (int i = 0; i < rnode.values_to_reply.Length; i++) { EXPRESSION des = rnode.values_to_reply[i]; int savestate = nextstate; if ((nextstate = ValidateDataTransfer(rules, nextstate, true, des, true)) < 0) { if (!next.astNode.ErrorReported && !rules.errorReported) { ERROR.ProtocolViolation(next.astNode.sourceContext, rules.ExpectedAtState(savestate, false)); next.astNode.ErrorReported = true; rules.errorReported = true; } } else if (nextstate == 0) // This was the last send/receive { nextstate = -1; } } next.AddStateFor(rules.id, nextstate); node.ForwardAllStatesExceptOneTo(next, rules.id); needtocopy = false; } } } else if (next.astNode is SEND_RECEIVE) { SEND_RECEIVE snode = next.astNode as SEND_RECEIVE; if (snode.call.call.callee is INSTANCE) { int id = ((INSTANCE)snode.call.call.callee).entity.unique; if (!exclude.Contains(id)) { if (ptotable.ContainsKey(id)) { Rules rules = ptotable[id]; foreach (int protocolState in node.GetStatesFor(rules.id)) { int nextstate = protocolState; if (snode.call.call != null) { for (int i = 0; i < snode.call.call.arguments.Length; i++) { EXPRESSION des = snode.call.call.arguments[i]; int savestate = nextstate; if ((nextstate = ValidateDataTransfer(rules, nextstate, false, des, true)) < 0) { if (!next.astNode.ErrorReported && !rules.errorReported) { ERROR.ProtocolViolation(next.astNode.sourceContext, rules.ExpectedAtState(savestate, true)); next.astNode.ErrorReported = true; rules.errorReported = true; } } else if (nextstate == 0) // This was the last send/receive { nextstate = -1; } } } if (snode.leftParts != null) { for (int i = 0; i < snode.leftParts.Length; i++) { EXPRESSION des = snode.leftParts[i]; int savestate = nextstate; if ((nextstate = ValidateDataTransfer(rules, nextstate, true, des, false)) < 0) { if (!next.astNode.ErrorReported && !rules.errorReported) { ERROR.ProtocolViolation(next.astNode.sourceContext, rules.ExpectedAtState(savestate, true)); next.astNode.ErrorReported = true; rules.errorReported = true; } } else if (nextstate == 0) // This was the last send/receive { nextstate = -1; } } } next.AddStateFor(rules.id, nextstate); node.ForwardAllStatesExceptOneTo(next, rules.id); needtocopy = false; } } else { ERROR.AcceptCalledForInvalidDialog(snode.sourceContext); } } } else { if (!snode.ErrorReported) { ERROR.ActivityVariableMustBeLocal(snode.sourceContext); } snode.ErrorReported = true; } } else if (next.astNode is CALL_STMT) { CALL_STMT cnode = next.astNode as CALL_STMT; if (cnode.call.callee is INSTANCE && (cnode.call.type is ABSTRACT_ACTIVITY_TYPE || cnode.call.type is ACTIVITY_TYPE)) { int id = ((INSTANCE)cnode.call.callee).entity.unique; if (!exclude.Contains(id)) { if (ptotable.ContainsKey(id)) { Rules rules = ptotable[id]; foreach (int protocolState in node.GetStatesFor(rules.id)) { int nextstate = protocolState; if (cnode.call != null) { for (int i = 0; i < cnode.call.arguments.Length; i++) { EXPRESSION des = cnode.call.arguments[i]; int savestate = nextstate; if ((nextstate = ValidateDataTransfer(rules, nextstate, false, des, true)) < 0) { if (!next.astNode.ErrorReported && !rules.errorReported) { ERROR.ProtocolViolation(next.astNode.sourceContext, rules.ExpectedAtState(savestate, true)); next.astNode.ErrorReported = true; rules.errorReported = true; } } else if (nextstate == 0) // This was the last send/receive { nextstate = -1; } } } next.AddStateFor(rules.id, nextstate); node.ForwardAllStatesExceptOneTo(next, rules.id); needtocopy = false; } } } else { ERROR.AcceptCalledForInvalidDialog(cnode.sourceContext); } } } if (needtocopy) { node.ForwardAllStatesTo(next); } if (!next.visited) { visitNext.Enqueue(next); } } } // We leave the graph. All protocols in the last node must be in -1 state foreach (Rules rule in ptotable.Values) { foreach (int protocolState in node.GetStatesFor(rule.id)) { if (!ValidateEnd(rule, protocolState) && !rule.errorReported) { ERROR.ProtocolNotCompleted(new SourceContext(defaultContext.Document, defaultContext.EndPos - 3, defaultContext.EndPos), rule.name, rule.ExpectedAtState(protocolState, true)); } } } return(true); }