DispatcherGenerator::CodeBranchGenerationResult DispatcherGenerator::generateOperatorCode( qReal::Id const ¤tNode) const { if (currentNode.element() == "FunctionCall") { return generateFunctionCallCode(currentNode); } if (currentNode.element() == "Action") { return generateActionCode(currentNode); } if (currentNode.element() == "InitialNode") { return generateInitialNodeCode(currentNode); } if (currentNode.element() == "ReturnAction") { return generateReturnActionCode(currentNode); } if (currentNode.element() == "DecisionNode") { generateDecisionNodeCode(currentNode); } return CodeBranchGenerationResult("", currentNode); }
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); }
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 ThreadsValidator::visitGeneral(const qReal::Id &id, const QList<LinkInfo> &links) { if (mSecondStage) { return; } if (mBlockThreads[id] == "@@unknown@@") { unknownThread(links); return; } QSet<QString> incomingThreads; for (const qReal::Id &link : mRepo.incomingLinks(id)) { const qReal::Id previousBlock = mRepo.otherEntityFromLink(link, id); if (mBlockThreads.contains(previousBlock)) { if (previousBlock.element() == "Fork") { incomingThreads.insert(mRepo.stringProperty(link, "Guard")); } else { /// @todo: In general case one block may belong to many threads. /// We must append all incomming thread lists here. incomingThreads.insert(mBlockThreads[previousBlock]); } } } if ((incomingThreads.size() != 1 && mStartNode != id) || incomingThreads.contains("@@unknown@@")) { unknownThread(links); return; } for (const LinkInfo &link : links) { if (!checkForConnected(link)) { return; } const qReal::Id nextBlock = link.target; if (!mBlockThreads.contains(nextBlock) || mBlockThreads[nextBlock].isEmpty()) { mSomethingChanged = true; mBlockThreads[nextBlock] = mBlockThreads[id]; } else if (mBlockThreads[nextBlock] != mBlockThreads[id] && mBlockThreads[nextBlock] != "@@unknown@@" && nextBlock.element() != "Join") { mSomethingChanged = true; mBlockThreads[nextBlock] = "@@unknown@@"; } } }
QList<SmartLine> AbstractSimpleElementGenerator::convertedCode(NxtOSEKRobotGenerator *nxtGen , const qReal::Id elementId, const qReal::Id logicElementId) { QString const elementType = elementId.element(); AbstractSimpleElementGenerator *currentSimpleElement = SimpleElementFactory::generator(elementType); QList<SmartLine> result = currentSimpleElement->convertElementIntoDirectCommand(nxtGen, elementId, logicElementId); return result; }
bool CommonBlocksFactory::elementMetatypeIs(const qReal::Id &element, const QString &metatype) { return element.type() == id(metatype); }
void PioneerStateMachineGenerator::processNode(NonZoneNode *thisNode, const qReal::Id &target) { SemanticNode *nextNode = nullptr; if (mAsynchronousNodes.contains(thisNode->id().element())) { if (not mSemanticTreeManager->isTopLevelNode(thisNode)) { // we in the if branches or smth like that if (not mConditionZonesQueue.isEmpty()) { const auto * const thenZone = std::get<2>(mConditionZonesQueue.last()); const auto * const elseZone = std::get<3>(mConditionZonesQueue.last()); auto * const parentZone = thisNode->parentZone(); if (thenZone == parentZone || elseZone == parentZone) { mBranchAsyncMarkers[parentZone] = true; } } } if (mSemanticTree->findNodeFor(target)) { trace("Asynchronous node, target visited."); // thisNode is asyncronous node that transfers control to already visited node. // Generated code for thisNode will initiate asynchronous action and all we need to do is to generate // transition to a state which will execute target block when this block finishes its asynchronous // operation. auto rightSibling = mSemanticTreeManager->anyRightSibling(thisNode); if (!rightSibling || !mSemanticTreeManager->isGotoNode(rightSibling)) { // Goto node may already be produced as a copy from previous instance of this node, so skipping it if // not needed. nextNode = produceGotoNode(target); mSemanticTreeManager->addAfter(thisNode, nextNode); } // already visited target if (nextNode->id().element() == "FiBlock") { if (not mConditionZonesQueue.isEmpty()) { if (std::get<1>(mConditionZonesQueue.last())) { mConditionZonesQueue.removeLast(); } else { reportAndExplainConditions(); return; } } else { reportError(tr("\"End If\" block occurs before \"If block\"")); return; } } if (!mLabeledNodes.contains(target)) { // Target node, despite being already visited, does not have a label, it means that it is a part of // a synchronous fragment. We copy that fragment from this node to the first asyncronous node and // label a start of the copied fragment. At the end of the fragment we will generate said // asynchronous node, which will initiate asynchronous operation, and then transition to its next // state, which will continue execution when operation is done. // // But first we need to lift copied fragment to a top level, since nextNode may be inside If branch. // Labeling something inside If branch will make generated code uncompilable. // // Getting parent node (i.e. If statement to the branch of which our node belongs). while (!mSemanticTreeManager->isTopLevelNode(nextNode)) { nextNode = mSemanticTreeManager->parent(nextNode); } // We shall copy nodes from synchronous fragment after end-of-handler node, if it is present. auto sibling = mSemanticTreeManager->anyRightSibling(nextNode); while (sibling != nullptr && isEndOfHandler(sibling)) { nextNode = mSemanticTreeManager->anyRightSibling(nextNode); sibling = mSemanticTreeManager->anyRightSibling(nextNode); } nextNode = copySynchronousFragment(nextNode, target, true); } if (mSemanticTreeManager->isTopLevelNode(thisNode) && !isEndOfHandler(nextNode) && !isEndOfHandler(mSemanticTreeManager->anyRightSibling(nextNode))) { SemanticNode * const endNode = produceEndOfHandlerNode(); mSemanticTreeManager->addAfter(nextNode, endNode); } } else { trace("Asynchronous node, target not visited."); // thisNode is asynchronous node that transfers control to a node that has not been visited yet. Generating // transition into a state associated with that node and then a new handler for target node itself. nextNode = mSemanticTreeManager->produceLabeledNode(target); if (!nextNode) { reportError(tr("Generation internal error, failed to create a node.")); return; } else { mLabeledNodes << nextNode->id(); } SemanticNode * const gotoNode = produceGotoNode(target); mSemanticTreeManager->addAfter(thisNode, gotoNode); // Labeled node can not be a part of a zone (i.e. "then" or "else" branch), it shall be generated in top // level zone. if (mSemanticTreeManager->isTopLevelNode(thisNode)) { SemanticNode * const endNode = produceEndOfHandlerNode(); mSemanticTreeManager->addAfter(gotoNode, endNode); mSemanticTreeManager->addAfter(endNode, nextNode); } else { // Getting parent node (i.e. If statement to the branch of which our node belongs). NonZoneNode *parent = mSemanticTreeManager->topLevelParent(thisNode); // Skipping "end" that finishes handler with If. SemanticNode * endOfHandler = findEndOfHandler(parent); if (not endOfHandler) { endOfHandler = produceEndOfHandlerNode(); mSemanticTreeManager->addAfter(parent, endOfHandler); } // Adding our labeled node denoting new handler after the end of a handler with If node. mSemanticTreeManager->addAfter(endOfHandler, nextNode); } // here we first time visiting FiBlock and it is descended from async node // it can be not actually in branch zone anymore (if async block appear before it) if (nextNode->id().element() == "FiBlock") { std::get<1>(mConditionZonesQueue.last()) = true; } } } else { if (!mSemanticTree->findNodeFor(target)) { trace("Synchronous node, target not visited."); if (target.element() == "FiBlock") { nextNode = mSemanticTreeManager->produceNode(target); if (mConditionZonesQueue.isEmpty()) { reportError(tr("\"End If\" block occurs before \"If block\"")); } else { auto conditionZone = mConditionZonesQueue.last(); SemanticNode *conditionalZone = std::get<0>(conditionZone); mSemanticTreeManager->addAfter(conditionalZone, nextNode); } return; } // It is not an asynchronous node, generating as-is. nextNode = mSemanticTreeManager->produceNode(target); mSemanticTreeManager->addAfter(thisNode, nextNode); } else { trace("Synchronous node, target visited."); if (target.element() == "FiBlock") { auto thenZone = std::get<2>(mConditionZonesQueue.last()); auto elseZone = std::get<3>(mConditionZonesQueue.last()); if (std::get<1>(mConditionZonesQueue.last()) || mBranchAsyncMarkers[thenZone] || mBranchAsyncMarkers[elseZone]) { reportAndExplainConditions(); } else { mConditionZonesQueue.removeLast(); nextNode = mSemanticTreeManager->produceNode(target); } return; } else { // Synchronous node leading to already visited node. Need some copypasting of synchronous fragments, // or else we will stall the program waiting for an event that was never initiated. nextNode = copySynchronousFragment(thisNode, target, false); } if (mSemanticTreeManager->isTopLevelNode(thisNode) && nextNode && !isEndOfHandler(nextNode)) { SemanticNode * const endNode = produceEndOfHandlerNode(); mSemanticTreeManager->addAfter(nextNode, endNode); } } } }
void ActionsManager::onActiveTabChanged(qReal::Id const &activeTabId) { bool const isDiagramTab = !activeTabId.isNull(); mRunAction.setEnabled(isDiagramTab); mStopRobotAction.setEnabled(isDiagramTab); }