28 #include <SimoxUtility/algorithm/string/string_tools.h>
29 #include <boost/format.hpp>
47 auto cppClasses = BuildClass(namespaces, reader->getRoot(
"State"), proxies, contextGenerationEnabled, groupName, variantInfo);
52 return writer->getString();
57 std::set<std::string> usedInnerNonBasicVariantDataTypes;
59 for (std::string typeName : GetUsedVariantTypes(stateNode))
69 if (!variantInfo->isBasic(type->typeId))
71 usedInnerNonBasicVariantDataTypes.insert(type->typeId);
75 return usedInnerNonBasicVariantDataTypes;
80 std::set<std::string> includePaths;
82 for (std::string typeName : GetUsedVariantTypes(stateNode))
92 if (!variantInfo->isBasic(type->typeId))
94 auto libEntry = variantInfo->findLibByVariant(type->typeId);
97 auto includes = libEntry->getVariantIncludes(type->typeId);
98 includePaths.insert(includes.begin(), includes.end());
106 std::vector<CppClassPtr> XmlStateBaseClassGenerator::BuildClass(std::vector<std::string> namespaces,
RapidXmlReaderNode stateNode, std::vector<std::string> proxies,
bool contextGenerationEnabled, std::string groupName,
VariantInfoPtr variantInfo)
108 std::vector<CppClassPtr> classes;
110 std::string baseClassName = className +
"GeneratedBase";
112 for (std::string& ns : namespaces)
114 ns = simox::alg::replace_all(ns,
"-",
"_");
117 CppClassPtr cppClass(
new CppClass(namespaces, baseClassName,
"template<typename StateType>"));
129 inClass->addInclude(
"<ArmarXCore/statechart/xmlstates/XMLState.h>");
131 if (contextGenerationEnabled)
139 cppClass->addInclude(fmt(
"\"%sStatechartContextBase.generated.h\"", groupName));
142 std::set<VariantInfo::LibEntryPtr> usedLibs;
144 for (std::string typeName : GetUsedVariantTypes(stateNode))
149 while (type->subType)
151 type = type->subType;
158 usedLibs.insert(lib);
162 inClass->addInclude(
"MISSING INCLUDE FOR " + type->typeId);
166 std::set<std::string> usedInnerNonBasicVariantDataImplementationTypes;
167 for (
auto& basicType : usedInnerNonBasicVariantDataTypes)
169 usedInnerNonBasicVariantDataImplementationTypes.insert(variantInfo->getDataTypeName(basicType));
173 for (
auto& include : variantIncludes)
175 cppClass->addInclude(fmt(
"<%s>", include));
178 std::vector<VariantInfo::LibEntryPtr> usedLibsVector(usedLibs.begin(), usedLibs.end());
181 return a->getName().compare(b->getName()) < 0;
184 std::vector<std::string> usedInnerNonBasicVariantDataTypesVector(usedInnerNonBasicVariantDataImplementationTypes.begin(), usedInnerNonBasicVariantDataImplementationTypes.end());
185 std::sort(usedInnerNonBasicVariantDataTypesVector.begin(), usedInnerNonBasicVariantDataTypesVector.end(), [](std::string
a, std::string b)
187 return a.compare(b) > 0;
190 inClass->addInclude(
"<ArmarXCore/core/system/FactoryCollectionBase.h>");
200 cppClass->addInherit(
"virtual public XMLStateTemplate < StateType >");
201 cppClass->addInherit(
"public XMLStateFactoryBase");
204 cppClass->addProtectedField(in);
207 cppClass->addProtectedField(local);
210 cppClass->addProtectedField(out);
213 inClass->addPrivateField(p);
214 localClass->addPrivateField(p);
215 outClass->addPrivateField(p);
217 inClass->addCtor((
"State *parent"))->addInitListEntry(
"parent",
"parent");
218 localClass->addCtor((
"State *parent"))->addInitListEntry(
"parent",
"parent");
219 outClass->addCtor((
"State *parent"))->addInitListEntry(
"parent",
"parent");
221 CppCtorPtr ctor = cppClass->addCtor(
"const XMLStateConstructorParams& stateData");
222 ctor->addInitListEntry(
"XMLState",
"stateData");
223 ctor->addInitListEntry(
"XMLStateTemplate < StateType > ",
"stateData");
224 ctor->addInitListEntry(
"in", fmt(
"%s(this)", inClass->getName()));
225 ctor->addInitListEntry(
"local", fmt(
"%s(this)", localClass->getName()));
226 ctor->addInitListEntry(
"out", fmt(
"%s(this)", outClass->getName()));
228 CppCtorPtr copyCtor = cppClass->addCtor(fmt(
"const %s &source", baseClassName));
229 copyCtor->addInitListEntry(
"IceUtil::Shared",
"source");
230 copyCtor->addInitListEntry(
"armarx::StateIceBase",
"source");
231 copyCtor->addInitListEntry(
"armarx::StateBase",
"source");
232 copyCtor->addInitListEntry(
"armarx::StateController",
"source");
233 copyCtor->addInitListEntry(
"armarx::State",
"source");
234 copyCtor->addInitListEntry(
"armarx::XMLState",
"source");
235 copyCtor->addInitListEntry(
"XMLStateTemplate < StateType > ",
"source");
236 copyCtor->addInitListEntry(
"in", fmt(
"%s(this)", inClass->getName()));
237 copyCtor->addInitListEntry(
"local", fmt(
"%s(this)", localClass->getName()));
238 copyCtor->addInitListEntry(
"out", fmt(
"%s(this)", outClass->getName()));
240 std::set<std::string> events;
243 events.insert(n.attribute_value(
"name"));
247 events.insert(n.attribute_value(
"name"));
250 for (
const std::string& name : events)
252 CppMethodPtr emitEvent = cppClass->addPublicMethod(fmt(
"void emit%s()", name));
253 emitEvent->addLine(fmt(
"State::sendEvent(State::createEvent(\"%s\"));", name));
254 CppMethodPtr installCondition = cppClass->addPublicMethod(fmt(
"void installConditionFor%s(const Term& condition, const std::string& desc = \"\")", name));
255 installCondition->addLine(fmt(
"State::installCondition(condition, State::createEvent(\"%s\"), desc);", name));
256 CppMethodPtr createEvent = cppClass->addPublicMethod(fmt(
"::armarx::EventPtr createEvent%s()", name));
257 createEvent->addLine(fmt(
"return State::createEvent(\"%s\");", name));
262 AddGet(p, inClass, variantInfo,
"getInput");
263 AddSet(p, inClass, variantInfo,
"setInput");
264 AddIsSet(p, inClass, variantInfo,
"isInputParameterSet");
269 AddGet(p, localClass, variantInfo,
"getLocal");
270 AddSet(p, localClass, variantInfo,
"setLocal");
271 AddIsSet(p, localClass, variantInfo,
"isLocalParameterSet");
276 AddGet(p, outClass, variantInfo,
"getOutput");
277 AddSet(p, outClass, variantInfo,
"setOutput");
278 AddIsSet(p, outClass, variantInfo,
"isOutputParameterSet");
281 if (contextGenerationEnabled)
283 for (std::string proxyId : proxies)
289 std::string name = p->getMemberName();
290 name[0] = toupper(name[0]);
291 CppMethodPtr getProxy = cppClass->addPublicMethod(fmt(
"const %s& get%s() const", p->getTypeName(), name));
292 getProxy->addLine(fmt(
"return StateBase::getContext<%sStatechartContextBase>()->%s();", groupName, p->getGetterName()));
300 for (std::pair<std::string, std::string> method : p->getStateMethods())
302 cppClass->addPublicMethod(method.first)->addLine(simox::alg::replace_all(method.second,
"%getContext%", fmt(
"StateBase::getContext<%sStatechartContextBase>()", groupName)));
307 ARMARX_WARNING_S <<
"Cannot find proxy info for " << proxyId <<
" for state " << className <<
" in group " << groupName;
315 getName->addLine(fmt(
"return \"%s\";", className));
316 cppClass->addPublicMethod(getName);
319 cloneFunc->addLine(
"StatePtr result = new StateType(*dynamic_cast<const StateType*>(this));");
320 cloneFunc->addLine(
"return result;");
321 cppClass->addPublicMethod(cloneFunc);
327 if (usedInnerNonBasicVariantDataTypesVector.size() > 0)
331 forceLibLoading->addLine(
"// Do not call this method.");
332 forceLibLoading->addLine(
"// The sole purpose of this method is to force the compiler/linker to include all libraries.");
336 for (std::string innerNonBasicVariantDataType : usedInnerNonBasicVariantDataTypesVector)
338 forceLibLoading->addLine(fmt(
"armarx::GenericFactory< %s, %s> ().create(%s::ice_staticId());", innerNonBasicVariantDataType, innerNonBasicVariantDataType, innerNonBasicVariantDataType));
343 cppClass->addPublicMethod(forceLibLoading);
346 AddTransitionCodeFunctions(stateNode, cppClass);
351 classes.push_back(inClass);
352 classes.push_back(localClass);
353 classes.push_back(outClass);
354 classes.push_back(cppClass);
358 std::set<std::string> XmlStateBaseClassGenerator::GetUsedVariantTypes(
RapidXmlReaderNode stateNode)
360 std::set<std::string> usedVariantTypes;
364 std::string type = p.attribute_value(
"type");
365 usedVariantTypes.insert(type);
370 std::string type = p.attribute_value(
"type");
371 usedVariantTypes.insert(type);
376 std::string type = p.attribute_value(
"type");
377 usedVariantTypes.insert(type);
380 return usedVariantTypes;
393 if (!containerInfo->subType)
395 std::string dataType = variantInfo->getDataTypeName(type);
396 std::string returnType = variantInfo->getReturnTypeName(type);
397 CppMethodPtr getMethod = targetClass->addPublicMethod(
boost::str(boost::format(
"%s get%s() const") % returnType % name), doc);
398 getMethod->addLine(boost::format(
"return parent->%s< %s>(\"%s\");") % parentGetMethodName % dataType % name);
407 else if (!containerInfo->subType->subType)
409 std::string innerDataType = variantInfo->getDataTypeName(containerInfo->subType->typeId);
410 std::string innerReturnType = variantInfo->getReturnTypeName(containerInfo->subType->typeId);
411 std::string containerType =
"NOT_FOUND";
412 std::string toStdContainerMethodName =
"NOT_FOUND";
413 std::string returnType =
"NOT_FOUND";
415 if (containerInfo->typeId ==
"::armarx::StringValueMapBase")
417 containerType =
"::armarx::StringValueMap";
418 toStdContainerMethodName =
"toStdMap";
419 returnType = fmt(
"std::map<std::string, %s>", innerReturnType);
421 else if (containerInfo->typeId ==
"::armarx::SingleTypeVariantListBase")
423 containerType =
"::armarx::SingleTypeVariantList";
424 toStdContainerMethodName =
"toStdVector";
425 returnType = fmt(
"std::vector< %s>", innerReturnType);
428 CppMethodPtr getMethod = targetClass->addPublicMethod(
boost::str(boost::format(
"%s get%s() const") % returnType % name), doc);
429 getMethod->addLine(boost::format(
"return parent->%s< %s>(\"%s\")->%s::%s< %s>();") % parentGetMethodName % containerType % name % containerType % toStdContainerMethodName % innerReturnType);
436 std::string innerDataType =
"NOT_FOUND";
437 std::string innerReturnType =
"NOT_FOUND";
439 if (containerInfo->subType->typeId ==
"::armarx::StringValueMapBase")
441 innerDataType =
"::armarx::StringValueMapPtr";
442 innerReturnType =
"::armarx::StringValueMapPtr";
444 else if (containerInfo->subType->typeId ==
"::armarx::SingleTypeVariantListBase")
446 innerDataType =
"::armarx::SingleTypeVariantListPtr";
447 innerReturnType =
"::armarx::SingleTypeVariantListPtr";
450 std::string containerType =
"NOT_FOUND";
451 std::string toStdContainerMethodName =
"NOT_FOUND";
452 std::string returnType =
"NOT_FOUND";
454 if (containerInfo->typeId ==
"::armarx::StringValueMapBase")
456 containerType =
"::armarx::StringValueMap";
457 toStdContainerMethodName =
"toContainerStdMap";
458 returnType = fmt(
"std::map<std::string, %s>", innerReturnType);
460 else if (containerInfo->typeId ==
"::armarx::SingleTypeVariantListBase")
462 containerType =
"::armarx::SingleTypeVariantList";
463 toStdContainerMethodName =
"toContainerStdVector";
464 returnType = fmt(
"std::vector< %s>", innerReturnType);
467 CppMethodPtr getMethod = targetClass->addPublicMethod(
boost::str(boost::format(
"%s get%s() const") % returnType % name), doc);
468 getMethod->addLine(boost::format(
"return parent->%s< %s>(\"%s\")->%s::%s< %s>();") % parentGetMethodName % containerType % name % containerType % toStdContainerMethodName % innerDataType);
476 CppMethodPtr getMethod = targetClass->addPublicMethod(
boost::str(boost::format(
"bool is%sSet() const") % name));
477 getMethod->addLine(boost::format(
"return parent->%s(\"%s\");") % parentTestParamMethodName % name);
488 if (!containerInfo->subType)
491 std::string dataType = variantInfo->getDataTypeName(containerInfo->typeId);
492 CppMethodPtr setMethod = targetClass->addPublicMethod(
boost::str(boost::format(
"void set%s(const %s & value)") % name % dataType), doc);
493 setMethod->addLine(boost::format(
"parent->%s(\"%s\", value);") % parentSetMethodName % name);
495 if (!variantInfo->isBasic(containerInfo->typeId))
498 std::string pointerType = containerInfo->typeId +
"Ptr";
499 CppMethodPtr ptrSetMethod = targetClass->addPublicMethod(
boost::str(boost::format(
"void set%s(const %s & value)") % name % pointerType));
500 ptrSetMethod->addLine(boost::format(
"parent->%s(\"%s\", *value);") % parentSetMethodName % name);
503 else if (!containerInfo->subType->subType)
506 std::string innerParamType = variantInfo->getReturnTypeName(containerInfo->subType->typeId);
507 std::string fromStdContainerMethod =
"NOT_FOUND";
508 std::string paramType =
"NOT_FOUND";
509 std::string containerType =
"NOT_FOUND";
511 if (containerInfo->typeId ==
"::armarx::StringValueMapBase")
513 containerType =
"::armarx::StringValueMapPtr";
514 fromStdContainerMethod = fmt(
"::armarx::StringValueMap::FromStdMap< %s>", innerParamType);
515 paramType = fmt(
"std::map<std::string, %s>", innerParamType);
517 else if (containerInfo->typeId ==
"::armarx::SingleTypeVariantListBase")
519 containerType =
"::armarx::SingleTypeVariantListPtr";
520 fromStdContainerMethod = fmt(
"::armarx::SingleTypeVariantList::FromStdVector< %s>", innerParamType);
521 paramType = fmt(
"std::vector< %s>", innerParamType);
524 CppMethodPtr setMethod = targetClass->addPublicMethod(
boost::str(boost::format(
"void set%s(const %s & value)") % name % paramType), doc);
525 setMethod->addLine(boost::format(
"%s container = %s(value);") % containerType % fromStdContainerMethod);
526 setMethod->addLine(boost::format(
"parent->%s(\"%s\", *container);") % parentSetMethodName % name);
531 std::string innerParamType =
"NOT_FOUND";
533 if (containerInfo->subType->typeId ==
"::armarx::StringValueMapBase")
536 innerParamType =
"::armarx::StringValueMapPtr";
538 else if (containerInfo->subType->typeId ==
"::armarx::SingleTypeVariantListBase")
541 innerParamType =
"::armarx::SingleTypeVariantListPtr";
544 std::string fromStdContainerMethod =
"NOT_FOUND";
545 std::string paramType =
"NOT_FOUND";
546 std::string containerType =
"NOT_FOUND";
548 if (containerInfo->typeId ==
"::armarx::StringValueMapBase")
550 containerType =
"::armarx::StringValueMapPtr";
551 fromStdContainerMethod = fmt(
"::armarx::StringValueMap::FromContainerStdMap< %s>", innerParamType);
552 paramType = fmt(
"std::map<std::string, %s>", innerParamType);
554 else if (containerInfo->typeId ==
"::armarx::SingleTypeVariantListBase")
556 containerType =
"::armarx::SingleTypeVariantListPtr";
557 fromStdContainerMethod = fmt(
"::armarx::SingleTypeVariantList::FromContainerStdVector< %s>", innerParamType);
558 paramType = fmt(
"std::vector< %s>", innerParamType);
561 CppMethodPtr setMethod = targetClass->addPublicMethod(
boost::str(boost::format(
"void set%s(const %s & value)") % name % paramType), doc);
562 setMethod->addLine(boost::format(
"%s container = %s(value);") % containerType % fromStdContainerMethod);
563 setMethod->addLine(boost::format(
"parent->%s(\"%s\", *container);") % parentSetMethodName % name);
570 auto transitionsNode = stateNode.
first_node(
"Transitions");
571 bool foundUserCodeTransition =
false;
574 const std::unordered_map<std::string, std::string> packageIncludePaths
576 {
"armar6_rt",
"armar6/rt"},
577 {
"armar6_skills",
"armar6/skills"},
581 const auto getPackageIncludePath = [&](
const std::string& packageName) -> std::string
583 if(packageIncludePaths.count(packageName))
585 return packageIncludePaths.at(packageName);
597 std::string toClass = tNode.attribute_value(
"toClass");
598 std::string toGroup = tNode.attribute_value(
"toGroup");
599 std::string toPackage = tNode.attribute_value(
"toPackage");
600 std::string fromClass = tNode.attribute_value(
"fromClass");
601 std::string fromGroup = tNode.attribute_value(
"fromGroup");
602 std::string fromPackage = tNode.attribute_value(
"fromPackage");
603 std::string fromStateInstanceName = tNode.attribute_value(
"from");
604 std::string eventName = tNode.attribute_value(
"eventName");
606 if (!toPackage.empty() && !toGroup.empty() && !toClass.empty())
608 const std::string packageIncludePath = getPackageIncludePath(toPackage);
609 targetClass->addInclude(fmt(
"<%s/statecharts/%s/%s.generated.h>", packageIncludePath, toGroup, toClass));
611 if (!fromPackage.empty() && !fromGroup.empty() && !fromClass.empty())
613 const std::string packageIncludePath = getPackageIncludePath(fromPackage);
614 targetClass->addInclude(fmt(
"<%s/statecharts/%s/%s.generated.h>", packageIncludePath, fromGroup, fromClass));
616 auto method = targetClass->addPublicMethod(
boost::str(boost::format(
"virtual void transition%sFrom%s(%s::%sIn &next, const %s::%sOut &prev) = 0;") %
617 eventName % fromStateInstanceName % toGroup % toClass % fromGroup % fromClass));
618 foundUserCodeTransition =
true;
622 if (foundUserCodeTransition)
625 CppMethodPtr method = targetClass->addPublicMethod(
"void defineSubstates()");
626 method->addLine(
"XMLStateTemplate < StateType >::defineSubstates();");
627 method->addLine(
"TransitionIceBase t;");
630 bool userCode = tNode.attribute_as_optional_bool(
"transitionCodeEnabled",
"1",
"0",
false);
633 std::string toClass = tNode.attribute_value(
"toClass");
634 std::string toGroup = tNode.attribute_value(
"toGroup");
635 std::string fromClass = tNode.attribute_value(
"fromClass");
636 std::string fromGroup = tNode.attribute_value(
"fromGroup");
637 std::string fromStateInstanceName = tNode.attribute_value(
"from");
638 std::string eventName = tNode.attribute_value(
"eventName");
639 CppMethodPtr helperMethod = targetClass->addPublicMethod(fmt(
"void _transition%sFrom%s(StateController* state, const StateIceBasePtr& nextState, const StateIceBasePtr& previousState)", eventName, fromStateInstanceName));
640 helperMethod->addLine(boost::format(
"%s::%sIn input(dynamic_cast<State*>(nextState.get()));") % toGroup % toClass);
641 helperMethod->addLine(boost::format(
"%s::%sOut output(dynamic_cast<State*>(previousState.get()));") % fromGroup % fromClass);
642 helperMethod->addLine(boost::format(
"%sGeneratedBase<StateType>* thisState = dynamic_cast<%sGeneratedBase<StateType>*>(state);") % currentStateName % currentStateName);
643 helperMethod->addLine(
"ARMARX_CHECK_EXPRESSION(thisState);");
644 helperMethod->addLine(boost::format(
"thisState->transition%sFrom%s(input, output);")
645 % eventName % fromStateInstanceName);
647 method->addLine(fmt(
"if (StateController::findTransition(\"%s\", \"%s\", t))", eventName, fromStateInstanceName));
648 method->addLine(fmt(
"\tthis->addTransitionFunction(t, std::bind(&%sGeneratedBase<StateType>::_transition%sFrom%s, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));", currentStateName, eventName, fromStateInstanceName));
656 std::string XmlStateBaseClassGenerator::fmt(
const std::string& fmt,
const std::string& arg1)
658 return str(boost::format(fmt) % arg1);
661 std::string XmlStateBaseClassGenerator::fmt(
const std::string& fmt,
const std::string& arg1,
const std::string& arg2)
663 return str(boost::format(fmt) % arg1 % arg2);
666 std::string XmlStateBaseClassGenerator::fmt(
const std::string& fmt,
const std::string& arg1,
const std::string& arg2,
const std::string& arg3)
668 return str(boost::format(fmt) % arg1 % arg2 % arg3);
671 std::string XmlStateBaseClassGenerator::generateDocString(
RapidXmlReaderNode stateNode,
const std::string& packageName,
const std::vector<std::string>& namespaces,
bool isPublicState)
674 auto docNode = stateNode.
first_node(
"Description");
675 std::string docString;
676 docString +=
"@class " + className +
"GeneratedBase\n";
678 if (namespaces.size() != 0)
680 docString +=
"@ingroup " + packageName +
"-" + *namespaces.rbegin() + (isPublicState ?
"" :
"-Substates") +
"\n";
683 if (docNode.is_valid())
685 docString += docNode.
value();
688 docString += generateParameterTableString(stateNode);
690 auto graphString = generateDotGraphString(stateNode);
692 if (!graphString.empty())
694 docString +=
"\n\n" + graphString;
700 std::string XmlStateBaseClassGenerator::generateParameterTableString(
RapidXmlReaderNode stateNode)
735 std::string XmlStateBaseClassGenerator::generateDotGraphString(
RapidXmlReaderNode stateNode)
738 auto transitions = stateNode.
first_node(
"Transitions");
740 if (transitions.first_node(
"Transition").is_valid())
743 result =
"\n \nTransitiongraph of the substates:\n";
744 result +=
"@dot\n\tdigraph States {\n";
748 curTransitionNode = curTransitionNode.next_sibling(
"Transition"))
750 if (curTransitionNode.has_attribute(
"from")
751 && curTransitionNode.has_attribute(
"to")
752 && curTransitionNode.has_attribute(
"eventName"))
755 curTransitionNode.attribute_value(
"to")
756 +
"[ label=\"" + curTransitionNode.attribute_value(
"eventName") +
"\" ];\n";
760 result +=
"}\n@enddot";
772 doc->addLine(fmt(
"@defgroup %s-%s-State %s", packageName, className, className));
773 std::string doxGroupName = fmt(
"%s-%s", packageName, namespaces.at(namespaces.size() - 1));
777 doxGroupName +=
"-Substates";
780 doc->addLine(fmt(
"@ingroup %s\n", doxGroupName));
782 std::string doxBrief;
785 if (doxDescription.size() > 0)
788 doxBrief = descLines[0];
789 doc->addLine(fmt(
"@brief %s\n", doxBrief));
793 doxBrief = fmt(
"@brief Brief description of state %s\n", className);
794 doc->addLine(doxBrief);
803 doc->addLine(
"Input parameters:");
804 doc->addParameterTable(inputParameters, variantInfo, communicator);
812 doc->addLine(
"Local parameters:");
813 doc->addParameterTable(localParameters, variantInfo, communicator);
821 doc->addLine(
"Output parameters");
822 doc->addParameterTable(outputParameters, variantInfo, communicator);
829 doc->addLine(
"Transition graph");
830 doc->addTransitionGraph(transitions);
834 doc->addLine(fmt(
"@class %sGeneratedBase", className));
836 if (namespaces.size() != 0)
840 doc->addLine(fmt(
"@ingroup %s-%s-State", packageName, className));
843 doc->addLine(fmt(
"For a documentation of this state see @ref %s-%s-State", packageName, className));
845 if (doxBrief.size() > 0)
847 doc->addLine(doxBrief);
850 doc->addLine(doxDescription.substr(0, 80));