void Repository::stackBefore(const qReal::Id &id, const qReal::Id &child, const qReal::Id &sibling) { if(!mObjects.contains(id)) { throw Exception("Repository: Moving child " + child.toString() + " of nonexistent object " + id.toString()); } if(!mObjects.contains(child)) { throw Exception("Repository: Moving nonexistent child " + child.toString()); } if(!mObjects.contains(sibling)) { throw Exception("Repository: Stacking before nonexistent child " + sibling.toString()); } mObjects[id]->stackBefore(child, sibling); }
void PioneerStateMachineGenerator::visitFinal(const qReal::Id &id, const QList<LinkInfo> &links) { generatorBase::GotoControlFlowGenerator::visitFinal(id, links); trace("Visiting final node: " + id.toString()); if (mErrorsOccured) { return; } // Here we are going to add finishing end-of-handler node in case it is missing (for example, diagrams like // "Initial Node" -> "Final Node" will not generate it automatically). // It is a kind of hack because asynchronous handler shall be a first-class entity and a zone node. auto nodes = mSemanticTreeManager->nodes(id); for (auto node : nodes) { if (!node) { continue; } SimpleNode * const thisNode = static_cast<SimpleNode *>(node); // Getting top level parent node for this node. NonZoneNode *parent = mSemanticTreeManager->topLevelParent(thisNode); // Searching for end-of-handler node. SemanticNode * endOfHandler = findEndOfHandler(parent); if (!endOfHandler) { // If not found, create and add one. endOfHandler = produceEndOfHandlerNode(); mSemanticTreeManager->addAfter(thisNode, endOfHandler); } } }
void PioneerStateMachineGenerator::visitConditional(const qReal::Id &id, const QList<LinkInfo> &links) { Q_UNUSED(links) trace("Visiting conditional node: " + id.toString()); if (mErrorsOccured) { return; } if (not mVisitedNodes.contains(id)) { ++mConditionals; } const QPair<LinkInfo, LinkInfo> branches(ifBranchesFor(id)); const LinkInfo thenLink = branches.first; const LinkInfo elseLink = branches.second; const auto nodes = mSemanticTreeManager->nodes(id); for (const auto node : nodes) { IfNode * const thisNode = static_cast<IfNode *>(node); mSemanticTreeManager->addToZone(thisNode->thenZone(), thenLink.target); mSemanticTreeManager->addToZone(thisNode->elseZone(), elseLink.target); mConditionZonesQueue.enqueue(std::make_tuple(thisNode, false, thisNode->thenZone(), thisNode->elseZone())); mBranchAsyncMarkers[thisNode->thenZone()] = false; mBranchAsyncMarkers[thisNode->elseZone()] = false; if (!mSemanticTreeManager->isTopLevelNode(thisNode)) { reportError(tr("Nested If's constructions is not allowed.")); return; } } }
void PioneerStateMachineGenerator::visitRegular(const qReal::Id &id, const QList<LinkInfo> &links) { // Base class method checks for subprogram calls, which is irrelevant for now, but does not hurt and hopefully // will be needed later. ControlFlowGeneratorBase::visitRegular(id, links); if (mErrorsOccured) { return; } if (id.element() == "InitialNode") { mLabeledNodes << links.first().target; } if (not mVisitedNodes.contains(id) && id.element() == "FiBlock") { ++mConditionalEnds; } trace("Visiting " + id.toString()); const qReal::Id target = links[0].target; QList<NonZoneNode *> nodesWithThisId = mSemanticTreeManager->nodes(id); for (auto thisNode : nodesWithThisId) { if (thisNode) { processNode(thisNode, target); } else { mErrorsOccured = true; return; } } if (mErrorsOccured) { return; } // Generation of a node may lead to sudden appearance of new copies of a node (for example, if this node was in a // branch of If statement that get copied when generating node, quite common in if-loop programs). So we need to // process new clones as well. auto updatedNodes = mSemanticTreeManager->nodes(id); while (updatedNodes.size() != nodesWithThisId.size()) { for (auto node : updatedNodes) { if (!nodesWithThisId.contains(node)) { processNode(node, target); nodesWithThisId.append(node); } } updatedNodes = mSemanticTreeManager->nodes(id); } doDeferredGotoGeneration(id, target); }