30 #include <boost/format.hpp>
32 #include <SimoxUtility/algorithm/string/string_tools.h>
47 const std::vector<std::string>& proxies,
48 bool contextGenerationEnabled,
49 std::string groupName,
52 auto cppClasses = BuildClass(namespaces,
53 reader->getRoot(
"State"),
55 contextGenerationEnabled,
62 return writer->getString();
69 std::set<std::string> usedInnerNonBasicVariantDataTypes;
71 for (std::string typeName : GetUsedVariantTypes(stateNode))
81 if (!variantInfo->isBasic(type->typeId))
83 usedInnerNonBasicVariantDataTypes.insert(type->typeId);
87 return usedInnerNonBasicVariantDataTypes;
94 std::set<std::string> includePaths;
96 for (std::string typeName : GetUsedVariantTypes(stateNode))
101 while (type->subType)
103 type = type->subType;
106 if (!variantInfo->isBasic(type->typeId))
108 auto libEntry = variantInfo->findLibByVariant(type->typeId);
111 auto includes = libEntry->getVariantIncludes(type->typeId);
112 includePaths.insert(includes.begin(), includes.end());
120 std::vector<CppClassPtr>
121 XmlStateBaseClassGenerator::BuildClass(std::vector<std::string> namespaces,
123 std::vector<std::string> proxies,
124 bool contextGenerationEnabled,
125 std::string groupName,
128 std::vector<CppClassPtr> classes;
130 std::string baseClassName = className +
"GeneratedBase";
132 for (std::string& ns : namespaces)
134 ns = simox::alg::replace_all(ns,
"-",
"_");
137 CppClassPtr cppClass(
new CppClass(namespaces, baseClassName,
"template<typename StateType>"));
149 inClass->addInclude(
"<ArmarXCore/statechart/xmlstates/XMLState.h>");
151 if (contextGenerationEnabled)
159 cppClass->addInclude(fmt(
"\"%sStatechartContextBase.generated.h\"", groupName));
162 std::set<VariantInfo::LibEntryPtr> usedLibs;
164 for (std::string typeName : GetUsedVariantTypes(stateNode))
169 while (type->subType)
171 type = type->subType;
178 usedLibs.insert(lib);
182 inClass->addInclude(
"MISSING INCLUDE FOR " + type->typeId);
185 std::set<std::string> usedInnerNonBasicVariantDataTypes =
187 std::set<std::string> usedInnerNonBasicVariantDataImplementationTypes;
188 for (
auto& basicType : usedInnerNonBasicVariantDataTypes)
190 usedInnerNonBasicVariantDataImplementationTypes.insert(
191 variantInfo->getDataTypeName(basicType));
194 std::set<std::string> variantIncludes =
196 for (
auto& include : variantIncludes)
198 cppClass->addInclude(fmt(
"<%s>", include));
201 std::vector<VariantInfo::LibEntryPtr> usedLibsVector(usedLibs.begin(), usedLibs.end());
202 std::sort(usedLibsVector.begin(),
203 usedLibsVector.end(),
205 { return a->getName().compare(b->getName()) < 0; });
207 std::vector<std::string> usedInnerNonBasicVariantDataTypesVector(
208 usedInnerNonBasicVariantDataImplementationTypes.begin(),
209 usedInnerNonBasicVariantDataImplementationTypes.end());
210 std::sort(usedInnerNonBasicVariantDataTypesVector.begin(),
211 usedInnerNonBasicVariantDataTypesVector.end(),
212 [](std::string
a, std::string b) { return a.compare(b) > 0; });
214 inClass->addInclude(
"<ArmarXCore/core/system/FactoryCollectionBase.h>");
224 cppClass->addInherit(
"virtual public XMLStateTemplate < StateType >");
225 cppClass->addInherit(
"public XMLStateFactoryBase");
228 cppClass->addProtectedField(in);
231 cppClass->addProtectedField(local);
234 cppClass->addProtectedField(out);
237 inClass->addPrivateField(p);
238 localClass->addPrivateField(p);
239 outClass->addPrivateField(p);
241 inClass->addCtor((
"State *parent"))->addInitListEntry(
"parent",
"parent");
242 localClass->addCtor((
"State *parent"))->addInitListEntry(
"parent",
"parent");
243 outClass->addCtor((
"State *parent"))->addInitListEntry(
"parent",
"parent");
245 CppCtorPtr ctor = cppClass->addCtor(
"const XMLStateConstructorParams& stateData");
246 ctor->addInitListEntry(
"XMLState",
"stateData");
247 ctor->addInitListEntry(
"XMLStateTemplate < StateType > ",
"stateData");
248 ctor->addInitListEntry(
"in", fmt(
"%s(this)", inClass->getName()));
249 ctor->addInitListEntry(
"local", fmt(
"%s(this)", localClass->getName()));
250 ctor->addInitListEntry(
"out", fmt(
"%s(this)", outClass->getName()));
252 CppCtorPtr copyCtor = cppClass->addCtor(fmt(
"const %s &source", baseClassName));
253 copyCtor->addInitListEntry(
"IceUtil::Shared",
"source");
254 copyCtor->addInitListEntry(
"armarx::StateIceBase",
"source");
255 copyCtor->addInitListEntry(
"armarx::StateBase",
"source");
256 copyCtor->addInitListEntry(
"armarx::StateController",
"source");
257 copyCtor->addInitListEntry(
"armarx::State",
"source");
258 copyCtor->addInitListEntry(
"armarx::XMLState",
"source");
259 copyCtor->addInitListEntry(
"XMLStateTemplate < StateType > ",
"source");
260 copyCtor->addInitListEntry(
"in", fmt(
"%s(this)", inClass->getName()));
261 copyCtor->addInitListEntry(
"local", fmt(
"%s(this)", localClass->getName()));
262 copyCtor->addInitListEntry(
"out", fmt(
"%s(this)", outClass->getName()));
264 std::set<std::string> events;
267 events.insert(n.attribute_value(
"name"));
271 events.insert(n.attribute_value(
"name"));
274 for (
const std::string& name : events)
276 CppMethodPtr emitEvent = cppClass->addPublicMethod(fmt(
"void emit%s()", name));
277 emitEvent->addLine(fmt(
"State::sendEvent(State::createEvent(\"%s\"));", name));
278 CppMethodPtr installCondition = cppClass->addPublicMethod(
279 fmt(
"void installConditionFor%s(const Term& condition, const std::string& desc = \"\")",
281 installCondition->addLine(
282 fmt(
"State::installCondition(condition, State::createEvent(\"%s\"), desc);", name));
284 cppClass->addPublicMethod(fmt(
"::armarx::EventPtr createEvent%s()", name));
285 createEvent->addLine(fmt(
"return State::createEvent(\"%s\");", name));
290 AddGet(p, inClass, variantInfo,
"getInput");
291 AddSet(p, inClass, variantInfo,
"setInput");
292 AddIsSet(p, inClass, variantInfo,
"isInputParameterSet");
297 AddGet(p, localClass, variantInfo,
"getLocal");
298 AddSet(p, localClass, variantInfo,
"setLocal");
299 AddIsSet(p, localClass, variantInfo,
"isLocalParameterSet");
304 AddGet(p, outClass, variantInfo,
"getOutput");
305 AddSet(p, outClass, variantInfo,
"setOutput");
306 AddIsSet(p, outClass, variantInfo,
"isOutputParameterSet");
309 if (contextGenerationEnabled)
311 for (std::string proxyId : proxies)
317 std::string name = p->getMemberName();
318 name[0] = toupper(name[0]);
320 fmt(
"const %s& get%s() const", p->getTypeName(), name));
322 fmt(
"return StateBase::getContext<%sStatechartContextBase>()->%s();",
324 p->getGetterName()));
332 for (std::pair<std::string, std::string> method : p->getStateMethods())
334 cppClass->addPublicMethod(method.first)
335 ->addLine(simox::alg::replace_all(
338 fmt(
"StateBase::getContext<%sStatechartContextBase>()", groupName)));
343 ARMARX_WARNING_S <<
"Cannot find proxy info for " << proxyId <<
" for state "
344 << className <<
" in group " << groupName;
352 getName->addLine(fmt(
"return \"%s\";", className));
353 cppClass->addPublicMethod(getName);
356 cloneFunc->addLine(
"StatePtr result = new StateType(*dynamic_cast<const StateType*>(this));");
357 cloneFunc->addLine(
"return result;");
358 cppClass->addPublicMethod(cloneFunc);
364 if (usedInnerNonBasicVariantDataTypesVector.size() > 0)
368 new CppMethod(
"void __attribute__((used)) __forceLibLoading()"));
369 forceLibLoading->addLine(
"// Do not call this method.");
370 forceLibLoading->addLine(
"// The sole purpose of this method is to force the "
371 "compiler/linker to include all libraries.");
375 for (std::string innerNonBasicVariantDataType : usedInnerNonBasicVariantDataTypesVector)
377 forceLibLoading->addLine(
378 fmt(
"armarx::GenericFactory< %s, %s> ().create(%s::ice_staticId());",
379 innerNonBasicVariantDataType,
380 innerNonBasicVariantDataType,
381 innerNonBasicVariantDataType));
386 cppClass->addPublicMethod(forceLibLoading);
389 AddTransitionCodeFunctions(stateNode, cppClass);
394 classes.push_back(inClass);
395 classes.push_back(localClass);
396 classes.push_back(outClass);
397 classes.push_back(cppClass);
401 std::set<std::string>
404 std::set<std::string> usedVariantTypes;
408 std::string type = p.attribute_value(
"type");
409 usedVariantTypes.insert(type);
414 std::string type = p.attribute_value(
"type");
415 usedVariantTypes.insert(type);
420 std::string type = p.attribute_value(
"type");
421 usedVariantTypes.insert(type);
424 return usedVariantTypes;
431 const std::string& parentGetMethodName)
440 if (!containerInfo->subType)
442 std::string dataType = variantInfo->getDataTypeName(type);
443 std::string returnType = variantInfo->getReturnTypeName(type);
445 boost::str(boost::format(
"%s get%s() const") % returnType % name), doc);
446 getMethod->addLine(boost::format(
"return parent->%s< %s>(\"%s\");") % parentGetMethodName %
456 else if (!containerInfo->subType->subType)
458 std::string innerDataType = variantInfo->getDataTypeName(containerInfo->subType->typeId);
459 std::string innerReturnType =
460 variantInfo->getReturnTypeName(containerInfo->subType->typeId);
461 std::string containerType =
"NOT_FOUND";
462 std::string toStdContainerMethodName =
"NOT_FOUND";
463 std::string returnType =
"NOT_FOUND";
465 if (containerInfo->typeId ==
"::armarx::StringValueMapBase")
467 containerType =
"::armarx::StringValueMap";
468 toStdContainerMethodName =
"toStdMap";
469 returnType = fmt(
"std::map<std::string, %s>", innerReturnType);
471 else if (containerInfo->typeId ==
"::armarx::SingleTypeVariantListBase")
473 containerType =
"::armarx::SingleTypeVariantList";
474 toStdContainerMethodName =
"toStdVector";
475 returnType = fmt(
"std::vector< %s>", innerReturnType);
479 boost::str(boost::format(
"%s get%s() const") % returnType % name), doc);
480 getMethod->addLine(boost::format(
"return parent->%s< %s>(\"%s\")->%s::%s< %s>();") %
481 parentGetMethodName % containerType % name % containerType %
482 toStdContainerMethodName % innerReturnType);
488 std::string innerDataType =
"NOT_FOUND";
489 std::string innerReturnType =
"NOT_FOUND";
491 if (containerInfo->subType->typeId ==
"::armarx::StringValueMapBase")
493 innerDataType =
"::armarx::StringValueMapPtr";
494 innerReturnType =
"::armarx::StringValueMapPtr";
496 else if (containerInfo->subType->typeId ==
"::armarx::SingleTypeVariantListBase")
498 innerDataType =
"::armarx::SingleTypeVariantListPtr";
499 innerReturnType =
"::armarx::SingleTypeVariantListPtr";
502 std::string containerType =
"NOT_FOUND";
503 std::string toStdContainerMethodName =
"NOT_FOUND";
504 std::string returnType =
"NOT_FOUND";
506 if (containerInfo->typeId ==
"::armarx::StringValueMapBase")
508 containerType =
"::armarx::StringValueMap";
509 toStdContainerMethodName =
"toContainerStdMap";
510 returnType = fmt(
"std::map<std::string, %s>", innerReturnType);
512 else if (containerInfo->typeId ==
"::armarx::SingleTypeVariantListBase")
514 containerType =
"::armarx::SingleTypeVariantList";
515 toStdContainerMethodName =
"toContainerStdVector";
516 returnType = fmt(
"std::vector< %s>", innerReturnType);
520 boost::str(boost::format(
"%s get%s() const") % returnType % name), doc);
521 getMethod->addLine(boost::format(
"return parent->%s< %s>(\"%s\")->%s::%s< %s>();") %
522 parentGetMethodName % containerType % name % containerType %
523 toStdContainerMethodName % innerDataType);
531 const std::string& parentTestParamMethodName)
536 targetClass->addPublicMethod(
boost::str(boost::format(
"bool is%sSet() const") % name));
537 getMethod->addLine(boost::format(
"return parent->%s(\"%s\");") % parentTestParamMethodName %
545 const std::string& parentSetMethodName)
553 if (!containerInfo->subType)
556 std::string dataType = variantInfo->getDataTypeName(containerInfo->typeId);
558 boost::str(boost::format(
"void set%s(const %s & value)") % name % dataType), doc);
559 setMethod->addLine(boost::format(
"parent->%s(\"%s\", value);") % parentSetMethodName %
562 if (!variantInfo->isBasic(containerInfo->typeId))
565 std::string pointerType = containerInfo->typeId +
"Ptr";
566 CppMethodPtr ptrSetMethod = targetClass->addPublicMethod(
567 boost::str(boost::format(
"void set%s(const %s & value)") % name % pointerType));
568 ptrSetMethod->addLine(boost::format(
"parent->%s(\"%s\", *value);") %
569 parentSetMethodName % name);
572 else if (!containerInfo->subType->subType)
575 std::string innerParamType = variantInfo->getReturnTypeName(containerInfo->subType->typeId);
576 std::string fromStdContainerMethod =
"NOT_FOUND";
577 std::string paramType =
"NOT_FOUND";
578 std::string containerType =
"NOT_FOUND";
580 if (containerInfo->typeId ==
"::armarx::StringValueMapBase")
582 containerType =
"::armarx::StringValueMapPtr";
583 fromStdContainerMethod =
584 fmt(
"::armarx::StringValueMap::FromStdMap< %s>", innerParamType);
585 paramType = fmt(
"std::map<std::string, %s>", innerParamType);
587 else if (containerInfo->typeId ==
"::armarx::SingleTypeVariantListBase")
589 containerType =
"::armarx::SingleTypeVariantListPtr";
590 fromStdContainerMethod =
591 fmt(
"::armarx::SingleTypeVariantList::FromStdVector< %s>", innerParamType);
592 paramType = fmt(
"std::vector< %s>", innerParamType);
596 boost::str(boost::format(
"void set%s(const %s & value)") % name % paramType), doc);
597 setMethod->addLine(boost::format(
"%s container = %s(value);") % containerType %
598 fromStdContainerMethod);
599 setMethod->addLine(boost::format(
"parent->%s(\"%s\", *container);") % parentSetMethodName %
605 std::string innerParamType =
"NOT_FOUND";
607 if (containerInfo->subType->typeId ==
"::armarx::StringValueMapBase")
610 innerParamType =
"::armarx::StringValueMapPtr";
612 else if (containerInfo->subType->typeId ==
"::armarx::SingleTypeVariantListBase")
615 innerParamType =
"::armarx::SingleTypeVariantListPtr";
618 std::string fromStdContainerMethod =
"NOT_FOUND";
619 std::string paramType =
"NOT_FOUND";
620 std::string containerType =
"NOT_FOUND";
622 if (containerInfo->typeId ==
"::armarx::StringValueMapBase")
624 containerType =
"::armarx::StringValueMapPtr";
625 fromStdContainerMethod =
626 fmt(
"::armarx::StringValueMap::FromContainerStdMap< %s>", innerParamType);
627 paramType = fmt(
"std::map<std::string, %s>", innerParamType);
629 else if (containerInfo->typeId ==
"::armarx::SingleTypeVariantListBase")
631 containerType =
"::armarx::SingleTypeVariantListPtr";
632 fromStdContainerMethod =
633 fmt(
"::armarx::SingleTypeVariantList::FromContainerStdVector< %s>", innerParamType);
634 paramType = fmt(
"std::vector< %s>", innerParamType);
638 boost::str(boost::format(
"void set%s(const %s & value)") % name % paramType), doc);
639 setMethod->addLine(boost::format(
"%s container = %s(value);") % containerType %
640 fromStdContainerMethod);
641 setMethod->addLine(boost::format(
"parent->%s(\"%s\", *container);") % parentSetMethodName %
650 auto transitionsNode = stateNode.
first_node(
"Transitions");
651 bool foundUserCodeTransition =
false;
654 const std::unordered_map<std::string, std::string> packageIncludePaths{
655 {
"armar6_rt",
"armar6/rt"}, {
"armar6_skills",
"armar6/skills"},
659 const auto getPackageIncludePath = [&](
const std::string& packageName) -> std::string
661 if (packageIncludePaths.count(packageName))
663 return packageIncludePaths.at(packageName);
675 std::string toClass = tNode.attribute_value(
"toClass");
676 std::string toGroup = tNode.attribute_value(
"toGroup");
677 std::string toPackage = tNode.attribute_value(
"toPackage");
678 std::string fromClass = tNode.attribute_value(
"fromClass");
679 std::string fromGroup = tNode.attribute_value(
"fromGroup");
680 std::string fromPackage = tNode.attribute_value(
"fromPackage");
681 std::string fromStateInstanceName = tNode.attribute_value(
"from");
682 std::string eventName = tNode.attribute_value(
"eventName");
684 if (!toPackage.empty() && !toGroup.empty() && !toClass.empty())
686 const std::string packageIncludePath = getPackageIncludePath(toPackage);
687 targetClass->addInclude(fmt(
688 "<%s/statecharts/%s/%s.generated.h>", packageIncludePath, toGroup, toClass));
690 if (!fromPackage.empty() && !fromGroup.empty() && !fromClass.empty())
692 const std::string packageIncludePath = getPackageIncludePath(fromPackage);
693 targetClass->addInclude(fmt(
"<%s/statecharts/%s/%s.generated.h>",
698 auto method = targetClass->addPublicMethod(
boost::str(
700 "virtual void transition%sFrom%s(%s::%sIn &next, const %s::%sOut &prev) = 0;") %
701 eventName % fromStateInstanceName % toGroup % toClass % fromGroup % fromClass));
702 foundUserCodeTransition =
true;
706 if (foundUserCodeTransition)
709 CppMethodPtr method = targetClass->addPublicMethod(
"void defineSubstates()");
710 method->addLine(
"XMLStateTemplate < StateType >::defineSubstates();");
711 method->addLine(
"TransitionIceBase t;");
715 tNode.attribute_as_optional_bool(
"transitionCodeEnabled",
"1",
"0",
false);
718 std::string toClass = tNode.attribute_value(
"toClass");
719 std::string toGroup = tNode.attribute_value(
"toGroup");
720 std::string fromClass = tNode.attribute_value(
"fromClass");
721 std::string fromGroup = tNode.attribute_value(
"fromGroup");
722 std::string fromStateInstanceName = tNode.attribute_value(
"from");
723 std::string eventName = tNode.attribute_value(
"eventName");
724 CppMethodPtr helperMethod = targetClass->addPublicMethod(
725 fmt(
"void _transition%sFrom%s(StateController* state, const StateIceBasePtr& "
726 "nextState, const StateIceBasePtr& previousState)",
728 fromStateInstanceName));
729 helperMethod->addLine(
730 boost::format(
"%s::%sIn input(dynamic_cast<State*>(nextState.get()));") %
732 helperMethod->addLine(
733 boost::format(
"%s::%sOut output(dynamic_cast<State*>(previousState.get()));") %
734 fromGroup % fromClass);
735 helperMethod->addLine(
736 boost::format(
"%sGeneratedBase<StateType>* thisState = "
737 "dynamic_cast<%sGeneratedBase<StateType>*>(state);") %
738 currentStateName % currentStateName);
739 helperMethod->addLine(
"ARMARX_CHECK_EXPRESSION(thisState);");
740 helperMethod->addLine(
741 boost::format(
"thisState->transition%sFrom%s(input, output);") % eventName %
742 fromStateInstanceName);
744 method->addLine(fmt(
"if (StateController::findTransition(\"%s\", \"%s\", t))",
746 fromStateInstanceName));
748 fmt(
"\tthis->addTransitionFunction(t, "
749 "std::bind(&%sGeneratedBase<StateType>::_transition%sFrom%s, this, "
750 "std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));",
753 fromStateInstanceName));
760 XmlStateBaseClassGenerator::fmt(
const std::string& fmt,
const std::string& arg1)
762 return str(boost::format(fmt) % arg1);
766 XmlStateBaseClassGenerator::fmt(
const std::string& fmt,
767 const std::string& arg1,
768 const std::string& arg2)
770 return str(boost::format(fmt) % arg1 % arg2);
774 XmlStateBaseClassGenerator::fmt(
const std::string& fmt,
775 const std::string& arg1,
776 const std::string& arg2,
777 const std::string& arg3)
779 return str(boost::format(fmt) % arg1 % arg2 % arg3);
784 const std::string& packageName,
785 const std::vector<std::string>& namespaces,
789 auto docNode = stateNode.
first_node(
"Description");
790 std::string docString;
791 docString +=
"@class " + className +
"GeneratedBase\n";
793 if (namespaces.size() != 0)
795 docString +=
"@ingroup " + packageName +
"-" + *namespaces.rbegin() +
796 (isPublicState ?
"" :
"-Substates") +
"\n";
799 if (docNode.is_valid())
801 docString += docNode.
value();
804 docString += generateParameterTableString(stateNode);
806 auto graphString = generateDotGraphString(stateNode);
808 if (!graphString.empty())
810 docString +=
"\n\n" + graphString;
817 XmlStateBaseClassGenerator::generateParameterTableString(
RapidXmlReaderNode stateNode)
853 auto transitions = stateNode.
first_node(
"Transitions");
855 if (transitions.first_node(
"Transition").is_valid())
858 result =
"\n \nTransitiongraph of the substates:\n";
859 result +=
"@dot\n\tdigraph States {\n";
863 curTransitionNode = curTransitionNode.next_sibling(
"Transition"))
865 if (curTransitionNode.has_attribute(
"from") && curTransitionNode.has_attribute(
"to") &&
866 curTransitionNode.has_attribute(
"eventName"))
869 curTransitionNode.attribute_value(
"to") +
"[ label=\"" +
870 curTransitionNode.attribute_value(
"eventName") +
"\" ];\n";
874 result +=
"}\n@enddot";
883 const std::string& packageName,
884 std::vector<std::string>& namespaces,
892 doc->addLine(fmt(
"@defgroup %s-%s-State %s", packageName, className, className));
893 std::string doxGroupName = fmt(
"%s-%s", packageName, namespaces.at(namespaces.size() - 1));
897 doxGroupName +=
"-Substates";
900 doc->addLine(fmt(
"@ingroup %s\n", doxGroupName));
902 std::string doxBrief;
905 if (doxDescription.size() > 0)
908 doxBrief = descLines[0];
909 doc->addLine(fmt(
"@brief %s\n", doxBrief));
913 doxBrief = fmt(
"@brief Brief description of state %s\n", className);
914 doc->addLine(doxBrief);
923 doc->addLine(
"Input parameters:");
924 doc->addParameterTable(inputParameters, variantInfo, communicator);
932 doc->addLine(
"Local parameters:");
933 doc->addParameterTable(localParameters, variantInfo, communicator);
941 doc->addLine(
"Output parameters");
942 doc->addParameterTable(outputParameters, variantInfo, communicator);
949 doc->addLine(
"Transition graph");
950 doc->addTransitionGraph(transitions);
954 doc->addLine(fmt(
"@class %sGeneratedBase", className));
956 if (namespaces.size() != 0)
960 doc->addLine(fmt(
"@ingroup %s-%s-State", packageName, className));
964 fmt(
"For a documentation of this state see @ref %s-%s-State", packageName, className));
966 if (doxBrief.size() > 0)
968 doc->addLine(doxBrief);
971 doc->addLine(doxDescription.substr(0, 80));