Example #1
0
DispatcherGenerator::CodeBranchGenerationResult DispatcherGenerator::generateOperatorCode(
		qReal::Id const &currentNode) 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);
}
Example #3
0
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;
		}
	}
}
Example #6
0
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);
			}
		}
	}
}
Example #10
0
void ActionsManager::onActiveTabChanged(qReal::Id const &activeTabId)
{
	bool const isDiagramTab = !activeTabId.isNull();
	mRunAction.setEnabled(isDiagramTab);
	mStopRobotAction.setEnabled(isDiagramTab);
}