// проверка дорожки участника public void checkSwimlane(Swimlane swimlane) { swimlaneCount++; // проверка на уникальность имени if (participantNames.Contains(swimlane.getName().ToLower())) { ADMistakeFactory.createMistake(MistakesSeriousness.mistakes[MISTAKES.REPEATED_NAME], MistakeAdapter.toString(MISTAKES.REPEATED_NAME), swimlane, ALL_MISTAKES.REPEATED_NAME); return; } else { participantNames.Add(swimlane.getName().ToLower()); } // проверка на заглавную букву if ((!swimlane.getName().Substring(0, 1).ToUpper().Equals(swimlane.getName().Substring(0, 1)))) { ADMistakeFactory.createMistake(Level.HARD, MistakeAdapter.toString(MISTAKES.SMALL_LETTER), swimlane, ALL_MISTAKES.SMALL_LETTER); } // проверка на колво дочерних элементов if (swimlane.ChildCount == 0) { ADMistakeFactory.createMistake(Level.EASY, MistakeAdapter.toString(MISTAKES.EMPTY_SWIMLANE), swimlane, ALL_MISTAKES.EMPTY_SWIMLANE); } // проверка на спец символ if (hasSpecialSymbol(swimlane.getName())) { ADMistakeFactory.createMistake(Level.HARD, MistakeAdapter.toString(MISTAKES.STRANGE_SYMBOL), swimlane, ALL_MISTAKES.STRANGE_SYMBOL); } }
// проверка перехода public void checkFlow(ControlFlow flow) { bool notCondButHaveMark = false; bool isCond = false; // если это не условие, проверяем подпись if (diagramElements.get(flow.getTarget()).getType() != ElementType.DECISION) { if (!flow.getText().Equals("")) { notCondButHaveMark = true; } } else { isCond = true; } if (diagramElements.get(flow.getSrc()).getType() != ElementType.DECISION) { if (!flow.getText().Equals("")) { if (!isCond) { ADMistakeFactory.createMistake(Level.HARD, MistakeAdapter.toString(MISTAKES.HAVE_MARK) + " - \"" + flow.getText() + "\"", flow, ALL_MISTAKES.HAVE_MARK); } } else if (notCondButHaveMark) { ADMistakeFactory.createMistake(Level.HARD, MistakeAdapter.toString(MISTAKES.HAVE_MARK) + " - \"" + flow.getText() + "\"", flow, ALL_MISTAKES.HAVE_MARK); } } }
// проверка активности public void checkActivity(ActivityNode activity, ADNodesList.ADNode node) { if (activity.getName().Length == 0) { ADMistakeFactory.createMistake(Level.HARD, MistakeAdapter.toString(MISTAKES.NO_NAME), node, ALL_MISTAKES.NO_NAME); } else { // проверка на уникальность имени if (activityNames.Contains(activity.getName().ToLower())) { ADMistakeFactory.createMistake(MistakesSeriousness.mistakes[MISTAKES.REPEATED_NAME], MistakeAdapter.toString(MISTAKES.REPEATED_NAME), diagramElements.getNode(activity.getId()), ALL_MISTAKES.REPEATED_NAME); return; } else { activityNames.Add(activity.getName().ToLower()); } // проверка на заглавную букву if ((!activity.getName().Substring(0, 1).ToUpper().Equals(activity.getName().Substring(0, 1)))) { ADMistakeFactory.createMistake(Level.HARD, MistakeAdapter.toString(MISTAKES.SMALL_LETTER), node, ALL_MISTAKES.SMALL_LETTER); } // получаем первое слово существительного и проверяем, что оно не заканчивается на ь или т string firstWord = activity.getName().Split(' ')[0]; //Console.WriteLine(firstWord); if (firstWord.EndsWith("те") || firstWord.EndsWith("чи") || firstWord.EndsWith("ти") || firstWord.EndsWith("ть") || firstWord.EndsWith("чь") || firstWord.EndsWith("т")) { ADMistakeFactory.createMistake(Level.EASY, MistakeAdapter.toString(MISTAKES.NOT_NOUN), node, ALL_MISTAKES.NOT_NOUN); } } }
public void check() { lexicalAnalizator.setDiagramElements(diagramElements); // прохождение по всем элементам и их проверка for (int i = 0; i < diagramElements.size(); i++) { BaseNode currentNode = diagramElements.get(i); switch (diagramElements.get(i).getType()) { case ElementType.FLOW: lexicalAnalizator.checkFlow((ControlFlow)diagramElements.get(i)); break; case ElementType.INITIAL_NODE: checkIfInPartion((DiagramElement)currentNode, "", diagramElements.getNode(i)); if (((DiagramElement)currentNode).outSize() == 0) { ADMistakeFactory.createMistake(MistakesSeriousness.mistakes[MISTAKES.NO_OUT], MistakeAdapter.toString(MISTAKES.NO_OUT), diagramElements.getNode(i), ALL_MISTAKES.NO_OUT); } checkInitial(); break; case ElementType.FINAL_NODE: checkIfInPartion((DiagramElement)currentNode, "", diagramElements.getNode(i)); if (((DiagramElement)currentNode).inSize() == 0) { ADMistakeFactory.createMistake(MistakesSeriousness.mistakes[MISTAKES.NO_OUT], MistakeAdapter.toString(MISTAKES.NO_IN), diagramElements.getNode(i), ALL_MISTAKES.NO_IN); } checkFinal(); break; case ElementType.FORK: checkIfInPartion((DiagramElement)currentNode, "", diagramElements.getNode(i)); checkInOut((DiagramElement)currentNode, "", diagramElements.getNode(i)); checkFork((ForkNode)currentNode, diagramElements.getNode(i)); break; case ElementType.JOIN: checkIfInPartion((DiagramElement)currentNode, "", diagramElements.getNode(i)); checkInOut((DiagramElement)currentNode, "", diagramElements.getNode(i)); break; case ElementType.MERGE: checkIfInPartion((DiagramElement)currentNode, "", diagramElements.getNode(i)); checkInOut((DiagramElement)currentNode, "", diagramElements.getNode(i)); break; case ElementType.ACTIVITY: lexicalAnalizator.checkActivity((ActivityNode)diagramElements.get(i), diagramElements.getNode(i)); checkIfInPartion((DiagramElement)currentNode, ((ActivityNode)currentNode).getName(), diagramElements.getNode(i)); checkInOut((DiagramElement)currentNode, ((ActivityNode)currentNode).getName(), diagramElements.getNode(i)); checkActivity((ActivityNode)diagramElements.get(i), diagramElements.getNode(i)); break; case ElementType.DECISION: lexicalAnalizator.checkDecision((DecisionNode)diagramElements.get(i), diagramElements.getNode(i)); checkIfInPartion((DiagramElement)currentNode, ((DecisionNode)currentNode).getQuestion(), diagramElements.getNode(i)); checkInOut((DiagramElement)currentNode, ((DecisionNode)currentNode).getQuestion(), diagramElements.getNode(i)); checkDecision((DecisionNode)diagramElements.get(i), diagramElements.getNode(i)); break; case ElementType.SWIMLANE: lexicalAnalizator.checkSwimlane((Swimlane)diagramElements.get(i)); break; case ElementType.UNKNOWN: break; } } if (finalCount == 0) { ADMistakeFactory.createMistake(MistakesSeriousness.mistakes[MISTAKES.NO_FINAL], MistakeAdapter.toString(MISTAKES.NO_FINAL), ALL_MISTAKES.NO_FINAL); } if (initialCount == 0) { ADMistakeFactory.createMistake(MistakesSeriousness.mistakes[MISTAKES.NO_INITIAL], MistakeAdapter.toString(MISTAKES.NO_INITIAL), ALL_MISTAKES.NO_INITIAL); } if (activityCount == 0) { ADMistakeFactory.createMistake(MistakesSeriousness.mistakes[MISTAKES.NO_ACTIVITIES], MistakeAdapter.toString(MISTAKES.NO_ACTIVITIES), ALL_MISTAKES.NO_ACTIVITIES); } if (lexicalAnalizator.swimlaneCount == 0) { ADMistakeFactory.createMistake(MistakesSeriousness.mistakes[MISTAKES.NO_SWIMLANE], MistakeAdapter.toString(MISTAKES.NO_SWIMLANE), ALL_MISTAKES.NO_SWIMLANE); } }
private void checkDecision(DecisionNode decision, ADNodesList.ADNode node) { bool checkAlt = true; // проверка, что альтернативы есть if (decision.alternativeSize() == 0) { ADMistakeFactory.createMistake(MistakesSeriousness.mistakes[MISTAKES.DO_NOT_HAVE_ALT], MistakeAdapter.toString(MISTAKES.DO_NOT_HAVE_ALT), node, ALL_MISTAKES.DO_NOT_HAVE_ALT); checkAlt = false; } // проверка, что альтернатив больше одной if (checkAlt) { if (decision.alternativeSize() == 1) { ADMistakeFactory.createMistake(MistakesSeriousness.mistakes[MISTAKES.ONLY_ONE_ALT], MistakeAdapter.toString(MISTAKES.ONLY_ONE_ALT), node, ALL_MISTAKES.ONLY_ONE_ALT); } } // проверка, что альтернативы не ведут в один и тот же элемент if (checkAlt) { for (int i = 0; i < decision.outSize() - 1; i++) { string targetId = ((ControlFlow)diagramElements.get(decision.getOutId(i))).getTarget(); for (int j = i + 1; j < decision.outSize(); j++) { if (targetId.Equals(((ControlFlow)diagramElements.get(decision.getOutId(j))).getTarget())) { ADMistakeFactory.createMistake(MistakesSeriousness.mistakes[MISTAKES.SAME_TARGET], MistakeAdapter.toString(MISTAKES.SAME_TARGET), node, ALL_MISTAKES.SAME_TARGET); } } if (diagramElements.get(targetId).getType() == ElementType.DECISION) { ADMistakeFactory.createMistake(MistakesSeriousness.mistakes[MISTAKES.NEXT_DECISION], MistakeAdapter.toString(MISTAKES.NEXT_DECISION), node, ALL_MISTAKES.NEXT_DECISION); } } // проверка на последовательность условных операторов string targetId2 = ((ControlFlow)diagramElements.get(decision.getOutId(decision.outSize() - 1))).getTarget(); if (diagramElements.get(targetId2).getType() == ElementType.DECISION) { ADMistakeFactory.createMistake(MistakesSeriousness.mistakes[MISTAKES.NEXT_DECISION], MistakeAdapter.toString(MISTAKES.NEXT_DECISION), node, ALL_MISTAKES.NEXT_DECISION); } } }
private void checkActivity(ActivityNode activity, ADNodesList.ADNode node) { activityCount++; // активность имеет больше одного выходящего перехода if (activity.outSize() >= 2) { ADMistakeFactory.createMistake(MistakesSeriousness.mistakes[MISTAKES.MORE_THAN_ONE_OUT], MistakeAdapter.toString(MISTAKES.MORE_THAN_ONE_OUT), node, ALL_MISTAKES.MORE_THAN_ONE_OUT); } }
private void checkInitial() { initialCount++; if (initialCount > 1) { ADMistakeFactory.createMistake(MistakesSeriousness.mistakes[MISTAKES.MORE_THAN_ONE_INIT], MistakeAdapter.toString(MISTAKES.MORE_THAN_ONE_INIT), ALL_MISTAKES.MORE_THAN_ONE_INIT); } }
private void checkFork(ForkNode fork, ADNodesList.ADNode node) { for (int i = 0; i < fork.outSize(); i++) { ElementType elementType = diagramElements.get(((ControlFlow)diagramElements.get(fork.getOutId(i))).getTarget()).getType(); Console.WriteLine("elementType=" + elementType); if (elementType != ElementType.ACTIVITY && elementType != ElementType.DECISION && elementType != ElementType.FORK && elementType != ElementType.MERGE) { ADMistakeFactory.createMistake(MistakesSeriousness.mistakes[MISTAKES.OUT_NOT_IN_ACT], MistakeAdapter.toString(MISTAKES.OUT_NOT_IN_ACT), node, ALL_MISTAKES.OUT_NOT_IN_ACT); } } }
/** * Проверка, что имеется хотя бы один входящий\выходящий переход */ private void checkInOut(DiagramElement currentNode, string name, ADNodesList.ADNode node) { if (currentNode is MergeNode || currentNode is JoinNode) { if ((currentNode).inSize() == 1) { ADMistakeFactory.createMistake(MistakesSeriousness.mistakes[MISTAKES.HAS_1_IN], MistakeAdapter.toString(MISTAKES.HAS_1_IN), node, ALL_MISTAKES.HAS_1_IN); } } if ((currentNode).inSize() == 0) { ADMistakeFactory.createMistake(MistakesSeriousness.mistakes[MISTAKES.NO_IN], MistakeAdapter.toString(MISTAKES.NO_IN), node, ALL_MISTAKES.NO_IN); } if ((currentNode).outSize() == 0) { ADMistakeFactory.createMistake(MistakesSeriousness.mistakes[MISTAKES.NO_OUT], MistakeAdapter.toString(MISTAKES.NO_OUT), node, ALL_MISTAKES.NO_OUT); } }
/** * Проверка, что элемент принадлежит какому-либо участнику */ private void checkIfInPartion(DiagramElement currentNode, string name, ADNodesList.ADNode node) { if (currentNode.getInPartition().Equals("")) { ADMistakeFactory.createMistake(MistakesSeriousness.mistakes[MISTAKES.NO_PARTION], MistakeAdapter.toString(MISTAKES.NO_PARTION), node, ALL_MISTAKES.NO_PARTION); } }
/// <summary> /// Распарсить XMI файл и создать объекты соответствующих классов /// </summary> /// <param name="diagram">Исходная диаграмма</param> /// <param name="hasJoinOrFork">Имеется ли join\fork</param> /// <returns></returns> public bool Parse(Diagram diagram, ref bool hasJoinOrFork) { xmlFile = diagram.doc; XmlNodeList xPackagedList; try { xPackagedList = xmlFile.GetElementsByTagName("packagedElement"); } catch (NullReferenceException) { //Console.WriteLine("[x] Тег packagedElement не найден"); return(false); } // получим корневой элемент XmlNode xRoot = FindActivePackageEl(xPackagedList); if (xRoot == null) { //Console.WriteLine("[x] Вид диаграммы не AD"); return(false); } var attr = xRoot.Attributes["xsi:type"]; if (attr == null) { //Console.WriteLine("[x] Не удалось распарсить xmi файл"); return(false); } if (!attr.Value.Equals("uml:Activity")) { //Console.WriteLine("[x] Вид диаграммы не AD"); return(false); } // пройтись по всем тегам и создать объекты foreach (XmlNode node in xRoot.ChildNodes) { var elAttr = node.Attributes["xsi:type"]; if (elAttr == null) { continue; } if (elAttr.Value == "uml:OpaqueAction" || elAttr.Value == "uml:InitialNode" || elAttr.Value == "uml:ActivityFinalNode" || elAttr.Value == "uml:FlowFinalNode" || elAttr.Value == "uml:DecisionNode" || elAttr.Value == "uml:MergeNode" || elAttr.Value == "uml:ForkNode" || elAttr.Value == "uml:JoinNode") { DiagramElement nodeFromXMI = null; switch (elAttr.Value) { // активность case "uml:OpaqueAction": nodeFromXMI = new ActivityNode(node.Attributes["xmi:id"].Value, AttrAdapter(node.Attributes["inPartition"]), AttrAdapter(node.Attributes["name"])); nodeFromXMI.setType(ElementType.ACTIVITY); adNodesList.addLast(nodeFromXMI); break; // узел инициализации case "uml:InitialNode": nodeFromXMI = new InitialNode(node.Attributes["xmi:id"].Value, AttrAdapter(node.Attributes["inPartition"])); nodeFromXMI.setType(ElementType.INITIAL_NODE); adNodesList.addLast(nodeFromXMI); break; // конечное состояние case "uml:ActivityFinalNode": case "uml:FlowFinalNode": nodeFromXMI = new FinalNode(node.Attributes["xmi:id"].Value, AttrAdapter(node.Attributes["inPartition"])); nodeFromXMI.setType(ElementType.FINAL_NODE); adNodesList.addLast(nodeFromXMI); break; // условный переход case "uml:DecisionNode": nodeFromXMI = new DecisionNode(node.Attributes["xmi:id"].Value, AttrAdapter(node.Attributes["inPartition"]), AttrAdapter(node.Attributes["question"])); nodeFromXMI.setType(ElementType.DECISION); adNodesList.addLast(nodeFromXMI); break; // узел слияния case "uml:MergeNode": nodeFromXMI = new MergeNode(node.Attributes["xmi:id"].Value, AttrAdapter(node.Attributes["inPartition"])); nodeFromXMI.setType(ElementType.MERGE); adNodesList.addLast(nodeFromXMI); break; // разветвитель case "uml:ForkNode": nodeFromXMI = new ForkNode(node.Attributes["xmi:id"].Value, AttrAdapter(node.Attributes["inPartition"])); nodeFromXMI.setType(ElementType.FORK); adNodesList.addLast(nodeFromXMI); hasJoinOrFork = true; break; // синхронизатор case "uml:JoinNode": nodeFromXMI = new JoinNode(node.Attributes["xmi:id"].Value, AttrAdapter(node.Attributes["inPartition"])); nodeFromXMI.setType(ElementType.JOIN); adNodesList.addLast(nodeFromXMI); hasJoinOrFork = true; break; } // добавляем ид входящих и выходящих переходов if (nodeFromXMI != null) { string idsIn = node.Attributes["incoming"]?.Value; string idsOut = node.Attributes["outgoing"]?.Value; nodeFromXMI.addIn(idsIn ?? ""); nodeFromXMI.addOut(idsOut ?? ""); } } // создаем переход else if (node.Attributes["xsi:type"].Value.Equals("uml:ControlFlow")) { // находим подпись перехода var markNode = node.ChildNodes[1]; string mark = markNode.Attributes["value"].Value.Trim(); // если подпись является "yes", значит это подпись по умолчанию ControlFlow temp = new ControlFlow(node.Attributes["xmi:id"].Value, mark.Equals("true") ? "" : mark); temp.setType(ElementType.FLOW); temp.setSrc(AttrAdapter(node.Attributes["source"])); temp.setTarget(AttrAdapter(node.Attributes["target"])); adNodesList.addLast(temp); } // создаем дорожку else if (node.Attributes["xsi:type"].Value.Equals("uml:ActivityPartition")) { Swimlane temp = new Swimlane(node.Attributes["xmi:id"].Value, AttrAdapter(node.Attributes["name"])) { ChildCount = node.Attributes["node"] == null ? 0 : node.Attributes["node"].Value.Split().Length }; temp.setType(ElementType.SWIMLANE); if (temp.Name != "") { diagram.Actors.Add(temp); } adNodesList.addLast(temp); } // неизвестный элемент else { var unknownNode = new UnknownNode(node.Attributes["xmi:id"].Value); unknownNode.setType(ElementType.UNKNOWN); unknownNodes.Add(unknownNode); } } XmlNode coordRoot = null; try { coordRoot = xmlFile.GetElementsByTagName("plane")[0]; } catch (NullReferenceException) { //Console.WriteLine("[x] Тег packagedElement не найден"); } if (coordRoot != null) { FindCoordinates(coordRoot, diagram); } for (int i = 0; i < adNodesList.size(); i++) { var node = adNodesList.get(i); if (node is DiagramElement) { var nodeFromXMI = (DiagramElement)node; switch (nodeFromXMI.getType()) { case ElementType.FINAL_NODE: if (nodeFromXMI.inSize() == 0) { // ошибка ADMistakeFactory.createMistake(MistakesSeriousness.mistakes[MISTAKES.NO_IN], MistakeAdapter.toString(MISTAKES.NO_IN), new ADNodesList.ADNode(nodeFromXMI), ALL_MISTAKES.NO_IN); } break; case ElementType.INITIAL_NODE: if (nodeFromXMI.outSize() == 0) { // ошибка ADMistakeFactory.createMistake(MistakesSeriousness.mistakes[MISTAKES.NO_OUT], MistakeAdapter.toString(MISTAKES.NO_OUT), new ADNodesList.ADNode(nodeFromXMI), ALL_MISTAKES.NO_OUT); } break; default: if (nodeFromXMI.inSize() == 0 || nodeFromXMI.outSize() == 0) { // ошибка if (nodeFromXMI.inSize() == 0) { ADMistakeFactory.createMistake(MistakesSeriousness.mistakes[MISTAKES.NO_IN], MistakeAdapter.toString(MISTAKES.NO_IN), new ADNodesList.ADNode(nodeFromXMI), ALL_MISTAKES.NO_IN); } if (nodeFromXMI.outSize() == 0) { ADMistakeFactory.createMistake(MistakesSeriousness.mistakes[MISTAKES.NO_OUT], MistakeAdapter.toString(MISTAKES.NO_OUT), new ADNodesList.ADNode(nodeFromXMI), ALL_MISTAKES.NO_OUT); } } break; } } } // ошибка - тип элемента не принадлежит AD foreach (var node in unknownNodes) { ADMistakeFactory.createMistake(MistakesSeriousness.mistakes[MISTAKES.FORBIDDEN_ELEMENT], MistakeAdapter.toString(MISTAKES.FORBIDDEN_ELEMENT), node, ALL_MISTAKES.FORBIDDEN_ELEMENT); } return(true); }
public void check(ADNodesList adList) { Queue <List <Token> > leaves = new Queue <List <Token> >(); // необработанные маски HashSet <string> masksInUsed = new HashSet <string>(adList.getPetriElementsCount()); // использованные маски // ищем начальное состояние ADNodesList.ADNode initNode = adList.findInitial(); var finalNode = adList.findFinal(); var indexesOfFinalNode = finalNode.Select(x => ((DiagramElement)x.getValue()).petriId).ToList(); // создаем маску и добавляем ее в необработанные List <Token> maskTmp = createEmptyMask(adList.getPetriElementsCount()); setNewPaleToken(maskTmp, ((DiagramElement)initNode.getValue()).petriId); leaves.Enqueue(maskTmp); masksInUsed.Add(maskToString(maskTmp)); // добавляем в множество использованных bool canReachFinal = false; List <List <Token> > stepResultMasks = new List <List <Token> >(); // содержит маски, кот могут получиться на каждом шаге string originMaskString = ""; // главный цикл прохода по всем элементам, участвующих в проверке while (leaves.Count > 0) { List <Token> originMask = leaves.Dequeue(); // берем первую маску originMaskString = maskToString(originMask); stepResultMasks.Clear(); List <Token> stepMask = copyMask(originMask); // маска, которую будем изменять по мере деактивации токенов stepResultMasks.Add(copyMask(stepMask)); // Если список масок не изменится, то будет тупик, тк текущая маска уже добавлена в использованные int i = 0; // Console.WriteLine("Or: " + maskToString(originMask)); // проходим по всем элементам маски, находим активированные // и проверяем, можно ли активировать следующий элемент for (int stepProhod = 0; stepProhod < 2; stepProhod++) // сначала проходим по условным, затем по остальным эл-м { i = 0; while (i < stepMask.Count) { if (stepProhod == 0 && adList.getNodeByPetriIndex(i).getValue().getType() != ElementType.DECISION) { i++; continue; // интересуют только эл-ты, содержащие токены на данном шаге } if (stepProhod == 0 && adList.getNodeByPetriIndex(i).getValue().getType() == ElementType.DECISION && stepMask[i].type != TOKEN) { i++; continue; // интересуют только эл-ты, содержащие токены на данном шаге } if (stepProhod == 1 && stepMask[i].type != TOKEN) { i++; continue; // интересуют только эл-ты, содержащие токены на данном шаге } // нашли активный элемент ADNodesList.ADNode curNode = adList.getNodeByPetriIndex(i); //индекс в списке совпадает с петри ид эл-та int curNodeIndex = ((DiagramElement)curNode.getValue()).petriId; List <int> colorsCurToken = new List <int>(stepMask[curNodeIndex].colors); // особо обрабатываем ситуации, когда элемент имеет несколько выходных переходов if (curNode.nextSize() > 1) { // если эл-т разветвитель, то последующее состояние единственно, однако надо установить несколько токенов за раз if (curNode.getValue().getType() == ElementType.FORK) { colorsCurToken.Add(generateRandomColor()); // активируем все следующие элементы for (int j = 0; j < curNode.nextSize(); j++) { // сразу после форка не может быть join'a, поэтому все эл-ты будут активированы int indexOfNewToken = ((DiagramElement)curNode.getNext(j).getValue()).petriId; // проверка, что эл-т не был раннее активирован if (wasAlreadyActive(indexOfNewToken, stepResultMasks, curNode.getNext(j))) { return; } // изменяем существующие результирующие маски updateStepMasks(((DiagramElement)curNode.getValue()).petriId, indexOfNewToken, stepResultMasks, colorsCurToken); } setNewEmptyToken(stepMask, curNodeIndex); } // если это условный оператор, то он порождает несколько возможных последующих состояний else { List <List <Token> > decisionMasks = new List <List <Token> >(); // содержит все возможные маски вариантов перемещения токена bool tokenWasRemoved = false; // активируем следующие элементы по одному for (int j = 0; j < curNode.nextSize(); j++) { int indexOfNewToken = ((DiagramElement)curNode.getNext(j).getValue()).petriId; // индекс активируемого эл-та // проверка, что эл-т не был раннее активирован if (wasAlreadyActive(indexOfNewToken, stepResultMasks, curNode.getNext(j))) { return; } // Join обрабатывается с помощью reverse проверки if ((curNode.getNext(j).getValue()).getType() == ElementType.JOIN) { List <List <Token> > temp = copyMasks(stepResultMasks); List <Token> result = activateJoin(curNode.getNext(j), stepMask, temp, colorsCurToken); if (result != null) { stepMask = result; decisionMasks.AddRange(temp); tokenWasRemoved = true; } } else { // в каждой существующей результирующей маске меняем токен и сохраняем в промежуточный список // в итоге получится новый список, содержащий несколько вариантов результирующих масок, // в каждом из которых создан новый токен в зависимости от активированного следующего эл-та foreach (List <Token> resultMask in stepResultMasks) { List <Token> temp = copyMask(resultMask); setToken(temp, indexOfNewToken, NEW_TOKEN, colorsCurToken); // добавляем новый токен setNewEmptyToken(temp, curNodeIndex); // удаляем токен текущего эл-та decisionMasks.Add(temp); tokenWasRemoved = true; } } } // изменяем маску шага и список результирующих масок, если токен был удален if (tokenWasRemoved) { setNewEmptyToken(stepMask, ((DiagramElement)curNode.getValue()).petriId); // меняем результирующую маску stepResultMasks = decisionMasks; } } } else // если выходной переход один { int indexOfNewToken = ((DiagramElement)curNode.getNext(0).getValue()).petriId; // проверка, что эл-т не был раннее активирован if (wasAlreadyActive(indexOfNewToken, stepResultMasks, curNode.getNext(0))) { return; } // если следующий Join if ((curNode.getNext(0).getValue()).getType() == ElementType.JOIN) { List <Token> result = activateJoin(curNode.getNext(0), stepMask, stepResultMasks, colorsCurToken); if (result != null) { stepMask = result; } } else { updateStepMasks(((DiagramElement)curNode.getValue()).petriId, indexOfNewToken, stepResultMasks, colorsCurToken); setNewEmptyToken(stepMask, curNodeIndex); } } i++; } } // в результирующих масках заменяем NEW_Token на TOKEN foreach (List <Token> stepResultMask in stepResultMasks) { stepResultMask.ForEach(x => x.type = x.type == NEW_TOKEN ? TOKEN : x.type); //Console.WriteLine("Re: " + maskToString(stepResultMask)); if (originMaskString == maskToString(stepResultMask)) { ADMistakeFactory.createMistake(MistakesSeriousness.mistakes[MISTAKES.DEAD_ROAD], MistakeAdapter.toString(MISTAKES.DEAD_ROAD), ALL_MISTAKES.DEAD_ROAD); //Console.WriteLine("Again?: "+originMaskString); return; } } // проверяем, что новой маски нет во множестве обработанных и добавляем в необработанные в таком случае foreach (List <Token> resultMask in stepResultMasks) { if (!findInMasksInUsed(masksInUsed, resultMask)) { int indexOfFinalNode = -1; // проверяем, не достигли ли конечной маркировки (существует путь позволяющий добраться хоть до какого-н finalNode) foreach (var ind in indexesOfFinalNode) { if (resultMask[ind].type == TOKEN) { indexOfFinalNode = ind; break; } } if (indexOfFinalNode != -1) { canReachFinal = true; if (resultMask[indexOfFinalNode].peekLastColor() != NO_COLOR) { ADMistakeFactory.createMistake(MistakesSeriousness.mistakes[MISTAKES.FINAL_COLOR_TOKEN], MistakeAdapter.toString(MISTAKES.FINAL_COLOR_TOKEN), ALL_MISTAKES.FINAL_COLOR_TOKEN); return; } //Проверка, что не осталось токенов int tokenCount = 0; for (int j = 0; j < resultMask.Count && tokenCount <= 1; j++) { if (resultMask[j].type == TOKEN) { tokenCount++; } } if (tokenCount > 1) { ADMistakeFactory.createMistake(MistakesSeriousness.mistakes[MISTAKES.MANY_TOKENS_IN_END], MistakeAdapter.toString(MISTAKES.MANY_TOKENS_IN_END), ALL_MISTAKES.MANY_TOKENS_IN_END); return; } } else { leaves.Enqueue(copyMask(resultMask)); } masksInUsed.Add(maskToString(resultMask)); // добавляем полученную маску в множество обработанных } } } // проверяем, что конечное состояние было достигнуто if (!canReachFinal) { ADMistakeFactory.createMistake(MistakesSeriousness.mistakes[MISTAKES.COULD_NOT_REACH_FINAL], MistakeAdapter.toString(MISTAKES.COULD_NOT_REACH_FINAL), ALL_MISTAKES.COULD_NOT_REACH_FINAL); } }
/** * Проверка был ли данный элемент раннее активирован. Если да, то проверка завершается */ private bool wasAlreadyActive(int tokenIndex, List <List <Token> > stepResultMasks, ADNodesList.ADNode curNode) { foreach (List <Token> stepResultMask in stepResultMasks) { if (stepResultMask[tokenIndex].type != NO_TOKEN) { if (curNode.getValue().getType() != ElementType.FINAL_NODE) { ADMistakeFactory.createMistake(MistakesSeriousness.mistakes[MISTAKES.TWO_TOKENS], MistakeAdapter.toString(MISTAKES.TWO_TOKENS), ALL_MISTAKES.TWO_TOKENS); } else { ADMistakeFactory.createMistake(MistakesSeriousness.mistakes[MISTAKES.MANY_TOKENS_IN_END], MistakeAdapter.toString(MISTAKES.MANY_TOKENS_IN_END), ALL_MISTAKES.MANY_TOKENS_IN_END); } return(true); } } return(false); }
// проверка условного перехода public void checkDecision(DecisionNode decision, ADNodesList.ADNode node) { // добавляем вопрос для перехода BaseNode flowIn = diagramElements.get(decision.getInId(0)); string quest = ((ControlFlow)flowIn).getText(); decision.setQuestion(quest.Trim()); // добавляем альтернативы -> проходим по всем выходящим переходам и получаем подписи for (int i = 0; i < decision.outSize(); i++) { BaseNode flow = diagramElements.get(decision.getOutId(i)); decision.addAlternative(((ControlFlow)flow).getText()); } // проверяем подписи альтернатив, если их больше одной bool checkAlt = decision.alternativeSize() >= 2; // поиск совпадающих названий if (checkAlt) { decision.findEqualAlternatives().ForEach(x => ADMistakeFactory.createMistake(Level.HARD, MistakeAdapter.toString(MISTAKES.REPEATED_ALT) + " - " + x, node, ALL_MISTAKES.REPEATED_ALT)); } // проверка на альтернативу без подписи if (checkAlt) { if (decision.findEmptyAlternative()) { ADMistakeFactory.createMistake(Level.HARD, MistakeAdapter.toString(MISTAKES.HAVE_EMPTY_ALT), node, ALL_MISTAKES.HAVE_EMPTY_ALT); } } // проверка, что альтернативы начинаются с заглавных букв //if (checkAlt) // for (int i = 0; i < decision.alternativeSize(); i++) // { // String alter = decision.getAlternative(i); // if (!alter.Equals("")) // if (!alter.Substring(0, 1).ToUpper().Equals(alter.Substring(0, 1))) // ADMistakeFactory.createMistake(Level.EASY, " альтернатива \"" + alter + "\"" + MistakeAdapter.toString(MISTAKES.SMALL_LETTER), node); // } bool checkQuest = true; // проверка, что имеется условие if (decision.getQuestion().Equals("")) { ADMistakeFactory.createMistake(Level.HARD, MistakeAdapter.toString(MISTAKES.HAVE_NOT_QUEST), node, ALL_MISTAKES.HAVE_NOT_QUEST); checkQuest = false; // дальнейшие проверки условия не требуются (его нет) } // проверка на заглавную букву if (checkQuest) { if ((!decision.getQuestion().Substring(0, 1).ToUpper().Equals(decision.getQuestion().Substring(0, 1)))) { ADMistakeFactory.createMistake(Level.EASY, MistakeAdapter.toString(MISTAKES.SMALL_LETTER), node, ALL_MISTAKES.SMALL_LETTER); } } // заканчивается на знак вопроса if (checkQuest) { if ((!decision.getQuestion().EndsWith("?"))) { ADMistakeFactory.createMistake(Level.EASY, MistakeAdapter.toString(MISTAKES.END_WITH_QUEST), node, ALL_MISTAKES.END_WITH_QUEST); } } }