XmlStateBaseClassGenerator.cpp
Go to the documentation of this file.
1 /*
2  * This file is part of ArmarX.
3  *
4  * Copyright (C) 2011-2016, High Performance Humanoid Technologies (H2T), Karlsruhe Institute of Technology (KIT), all rights reserved.
5  *
6  * ArmarX is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 as
8  * published by the Free Software Foundation.
9  *
10  * ArmarX is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program. If not, see <http://www.gnu.org/licenses/>.
17  *
18  * @package
19  * @author
20  * @date
21  * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
22  * GNU General Public License
23  */
25 
27 //#include <ArmarXCore/core/system/LibRegistryBase.h>
28 #include <filesystem>
29 
30 #include <boost/format.hpp>
31 
32 #include <SimoxUtility/algorithm/string/string_tools.h>
33 
37 
38 using namespace armarx;
39 
41 {
42 }
43 
44 std::string
45 XmlStateBaseClassGenerator::GenerateCpp(std::vector<std::string> namespaces,
46  RapidXmlReaderPtr reader,
47  const std::vector<std::string>& proxies,
48  bool contextGenerationEnabled,
49  std::string groupName,
50  VariantInfoPtr variantInfo)
51 {
52  auto cppClasses = BuildClass(namespaces,
53  reader->getRoot("State"),
54  proxies,
55  contextGenerationEnabled,
56  groupName,
57  variantInfo);
58 
59  CppWriterPtr writer(new CppWriter(true));
60  writer->body.line();
61  CppClass::WriteCpp(cppClasses, writer);
62  return writer->getString();
63 }
64 
65 std::set<std::string>
67  VariantInfoPtr variantInfo)
68 {
69  std::set<std::string> usedInnerNonBasicVariantDataTypes;
70 
71  for (std::string typeName : GetUsedVariantTypes(stateNode))
72  {
73  ContainerTypePtr type = VariantContainerType::FromString(typeName);
74 
75  // Find the inner type, all outer types are containers. If there is no container type->subType is null
76  while (type->subType)
77  {
78  type = type->subType;
79  }
80 
81  if (!variantInfo->isBasic(type->typeId))
82  {
83  usedInnerNonBasicVariantDataTypes.insert(type->typeId);
84  }
85  }
86 
87  return usedInnerNonBasicVariantDataTypes;
88 }
89 
90 std::set<std::string>
92  VariantInfoPtr variantInfo)
93 {
94  std::set<std::string> includePaths;
95 
96  for (std::string typeName : GetUsedVariantTypes(stateNode))
97  {
98  ContainerTypePtr type = VariantContainerType::FromString(typeName);
99 
100  // Find the inner type, all outer types are containers. If there is no container type->subType is null
101  while (type->subType)
102  {
103  type = type->subType;
104  }
105 
106  if (!variantInfo->isBasic(type->typeId))
107  {
108  auto libEntry = variantInfo->findLibByVariant(type->typeId);
109  if (libEntry)
110  {
111  auto includes = libEntry->getVariantIncludes(type->typeId);
112  includePaths.insert(includes.begin(), includes.end());
113  }
114  }
115  }
116 
117  return includePaths;
118 }
119 
120 std::vector<CppClassPtr>
121 XmlStateBaseClassGenerator::BuildClass(std::vector<std::string> namespaces,
122  RapidXmlReaderNode stateNode,
123  std::vector<std::string> proxies,
124  bool contextGenerationEnabled,
125  std::string groupName,
126  VariantInfoPtr variantInfo)
127 {
128  std::vector<CppClassPtr> classes;
129  std::string className = stateNode.attribute_value("name");
130  std::string baseClassName = className + "GeneratedBase";
131 
132  for (std::string& ns : namespaces)
133  {
134  ns = simox::alg::replace_all(ns, "-", "_");
135  }
136 
137  CppClassPtr cppClass(new CppClass(namespaces, baseClassName, "template<typename StateType>"));
138 
139  // auto docString = generateDocString(stateNode, packageName, namespaces, isPublicState);
140  // cppClass->addClassDoc(docString);
141  // DoxDocPtr doxDoc = generateDoxDoc(stateNode, packageName, namespaces, isPublicState, variantInfo, communicator);
142  // cppClass->addClassDoc(doxDoc);
143 
144 
145  CppClassPtr inClass(new CppClass(namespaces, className + "In"));
146  CppClassPtr localClass(new CppClass(namespaces, className + "Local"));
147  CppClassPtr outClass(new CppClass(namespaces, className + "Out"));
148 
149  inClass->addInclude("<ArmarXCore/statechart/xmlstates/XMLState.h>");
150 
151  if (contextGenerationEnabled)
152  {
153  /*std::stringstream ssNesting;
154  for(int i = 0; i < nestingLevel; i++)
155  {
156  ssNesting << "../";
157  }
158  cppClass->addInclude(fmt("\"%s%sStatechartContext.generated.h\"", ssNesting.str(), groupName));*/
159  cppClass->addInclude(fmt("\"%sStatechartContextBase.generated.h\"", groupName));
160  }
161 
162  std::set<VariantInfo::LibEntryPtr> usedLibs;
163 
164  for (std::string typeName : GetUsedVariantTypes(stateNode))
165  {
166  ContainerTypePtr type = VariantContainerType::FromString(typeName);
167 
168  // Find the inner type, all outer types are containers. If there is no container type->subType is null
169  while (type->subType)
170  {
171  type = type->subType;
172  }
173 
174  VariantInfo::LibEntryPtr lib = variantInfo->findLibByVariant(type->typeId);
175 
176  if (lib)
177  {
178  usedLibs.insert(lib);
179  }
180  else
181  {
182  inClass->addInclude("MISSING INCLUDE FOR " + type->typeId);
183  }
184  }
185  std::set<std::string> usedInnerNonBasicVariantDataTypes =
186  GetUsedInnerNonBasicVariantTypes(stateNode, variantInfo);
187  std::set<std::string> usedInnerNonBasicVariantDataImplementationTypes;
188  for (auto& basicType : usedInnerNonBasicVariantDataTypes)
189  {
190  usedInnerNonBasicVariantDataImplementationTypes.insert(
191  variantInfo->getDataTypeName(basicType));
192  }
193 
194  std::set<std::string> variantIncludes =
195  GetIncludesForInnerNonBasicVariantTypes(stateNode, variantInfo);
196  for (auto& include : variantIncludes)
197  {
198  cppClass->addInclude(fmt("<%s>", include));
199  }
200 
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; });
206 
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; });
213 
214  inClass->addInclude("<ArmarXCore/core/system/FactoryCollectionBase.h>");
215 
216  // for (VariantInfo::LibEntryPtr lib : usedLibsVector)
217  // {
218  // for (std::string include : lib->getFactoryIncludes())
219  // {
220  // cppClass->addInclude(fmt("<%s>", include));
221  // }
222  // }
223 
224  cppClass->addInherit("virtual public XMLStateTemplate < StateType >");
225  cppClass->addInherit("public XMLStateFactoryBase");
226 
227  CppFieldPtr in = CppFieldPtr(new CppField{inClass->getName(), "in"});
228  cppClass->addProtectedField(in);
229 
230  CppFieldPtr local = CppFieldPtr(new CppField{localClass->getName(), "local"});
231  cppClass->addProtectedField(local);
232 
233  CppFieldPtr out = CppFieldPtr(new CppField{outClass->getName(), "out"});
234  cppClass->addProtectedField(out);
235 
236  CppFieldPtr p = CppFieldPtr(new CppField{"State*", "parent"});
237  inClass->addPrivateField(p);
238  localClass->addPrivateField(p);
239  outClass->addPrivateField(p);
240 
241  inClass->addCtor(("State *parent"))->addInitListEntry("parent", "parent");
242  localClass->addCtor(("State *parent"))->addInitListEntry("parent", "parent");
243  outClass->addCtor(("State *parent"))->addInitListEntry("parent", "parent");
244 
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()));
251 
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()));
263 
264  std::set<std::string> events;
265  for (RapidXmlReaderNode n : stateNode.nodes("Events", "Event"))
266  {
267  events.insert(n.attribute_value("name"));
268  }
269  for (RapidXmlReaderNode n : stateNode.nodes("Substates", "EndState"))
270  {
271  events.insert(n.attribute_value("name"));
272  }
273 
274  for (const std::string& name : events)
275  {
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 = \"\")",
280  name));
281  installCondition->addLine(
282  fmt("State::installCondition(condition, State::createEvent(\"%s\"), desc);", name));
283  CppMethodPtr createEvent =
284  cppClass->addPublicMethod(fmt("::armarx::EventPtr createEvent%s()", name));
285  createEvent->addLine(fmt("return State::createEvent(\"%s\");", name));
286  }
287 
288  for (RapidXmlReaderNode p : stateNode.nodes("InputParameters", "Parameter"))
289  {
290  AddGet(p, inClass, variantInfo, "getInput");
291  AddSet(p, inClass, variantInfo, "setInput");
292  AddIsSet(p, inClass, variantInfo, "isInputParameterSet");
293  }
294 
295  for (RapidXmlReaderNode p : stateNode.nodes("LocalParameters", "Parameter"))
296  {
297  AddGet(p, localClass, variantInfo, "getLocal");
298  AddSet(p, localClass, variantInfo, "setLocal");
299  AddIsSet(p, localClass, variantInfo, "isLocalParameterSet");
300  }
301 
302  for (RapidXmlReaderNode p : stateNode.nodes("OutputParameters", "Parameter"))
303  {
304  AddGet(p, outClass, variantInfo, "getOutput");
305  AddSet(p, outClass, variantInfo, "setOutput");
306  AddIsSet(p, outClass, variantInfo, "isOutputParameterSet");
307  }
308 
309  if (contextGenerationEnabled)
310  {
311  for (std::string proxyId : proxies)
312  {
313  VariantInfo::ProxyEntryPtr p = variantInfo->getProxyEntry(proxyId);
314 
315  if (p)
316  {
317  std::string name = p->getMemberName();
318  name[0] = toupper(name[0]);
319  CppMethodPtr getProxy = cppClass->addPublicMethod(
320  fmt("const %s& get%s() const", p->getTypeName(), name));
321  getProxy->addLine(
322  fmt("return StateBase::getContext<%sStatechartContextBase>()->%s();",
323  groupName,
324  p->getGetterName()));
325  // std::string include = fmt("<%s>", p->getIncludePath());
326 
327  // if (!cppClass->hasInclude(include))
328  // {
329  // cppClass->addInclude(include);
330  // }
331 
332  for (std::pair<std::string, std::string> method : p->getStateMethods())
333  {
334  cppClass->addPublicMethod(method.first)
335  ->addLine(simox::alg::replace_all(
336  method.second,
337  "%getContext%",
338  fmt("StateBase::getContext<%sStatechartContextBase>()", groupName)));
339  }
340  }
341  else
342  {
343  ARMARX_WARNING_S << "Cannot find proxy info for " << proxyId << " for state "
344  << className << " in group " << groupName;
345  ARMARX_WARNING_S << "VariantInfo: " << variantInfo->getDebugInfo();
346  }
347  }
348  }
349 
350 
351  CppMethodPtr getName(new CppMethod("static std::string GetName()"));
352  getName->addLine(fmt("return \"%s\";", className));
353  cppClass->addPublicMethod(getName);
354 
355  CppMethodPtr cloneFunc(new CppMethod("StateBasePtr clone() const override"));
356  cloneFunc->addLine("StatePtr result = new StateType(*dynamic_cast<const StateType*>(this));");
357  cloneFunc->addLine("return result;");
358  cppClass->addPublicMethod(cloneFunc);
359 
360  // CppMethodPtr createEmptyCopyFunc(new CppMethod("StateBasePtr createEmptyCopy() const override"));
361  // createEmptyCopyFunc->addLine("return new StateType();");
362  // cppClass->addMethod(createEmptyCopyFunc);
363 
364  if (usedInnerNonBasicVariantDataTypesVector.size() > 0)
365  {
366  // Add special method that uses all non-basic types to force compiler/linker to include/load all libraries in binary (ensure GCC does not optimise it out).
367  CppMethodPtr forceLibLoading(
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.");
372 
373  int typeNr = 1;
374 
375  for (std::string innerNonBasicVariantDataType : usedInnerNonBasicVariantDataTypesVector)
376  {
377  forceLibLoading->addLine(
378  fmt("armarx::GenericFactory< %s, %s> ().create(%s::ice_staticId());",
379  innerNonBasicVariantDataType,
380  innerNonBasicVariantDataType,
381  innerNonBasicVariantDataType));
382 
383  typeNr++;
384  }
385 
386  cppClass->addPublicMethod(forceLibLoading);
387  }
388 
389  AddTransitionCodeFunctions(stateNode, cppClass);
390 
391  /*CppMethodPtr createInstance(new CppMethod("static XMLStateFactoryBasePtr CreateInstance(XMLStateConstructorParams stateData)"));
392  createInstance->addLine(fmt("return XMLStateFactoryBasePtr(new %s(stateData));", className));
393  cppClass->addMethod(createInstance);*/
394  classes.push_back(inClass);
395  classes.push_back(localClass);
396  classes.push_back(outClass);
397  classes.push_back(cppClass);
398  return classes;
399 }
400 
401 std::set<std::string>
402 XmlStateBaseClassGenerator::GetUsedVariantTypes(RapidXmlReaderNode stateNode)
403 {
404  std::set<std::string> usedVariantTypes;
405 
406  for (RapidXmlReaderNode p : stateNode.nodes("InputParameters", "Parameter"))
407  {
408  std::string type = p.attribute_value("type");
409  usedVariantTypes.insert(type);
410  }
411 
412  for (RapidXmlReaderNode p : stateNode.nodes("LocalParameters", "Parameter"))
413  {
414  std::string type = p.attribute_value("type");
415  usedVariantTypes.insert(type);
416  }
417 
418  for (RapidXmlReaderNode p : stateNode.nodes("OutputParameters", "Parameter"))
419  {
420  std::string type = p.attribute_value("type");
421  usedVariantTypes.insert(type);
422  }
423 
424  return usedVariantTypes;
425 }
426 
427 void
428 XmlStateBaseClassGenerator::AddGet(RapidXmlReaderNode node,
429  CppClassPtr targetClass,
430  VariantInfoPtr variantInfo,
431  const std::string& parentGetMethodName)
432 {
433  std::string name = node.attribute_value("name");
434  std::string type = node.attribute_value("type");
435  std::string doc = node.first_node_value_or_default("Description", "");
436  ContainerTypePtr containerInfo = VariantContainerType::FromString(type);
437 
438  // No Container, generated output:
439  // [returnType] get[Name]() { return parent->[getInput|getLocal|getOutput]<[dataType]>("[Name]"); }
440  if (!containerInfo->subType)
441  {
442  std::string dataType = variantInfo->getDataTypeName(type);
443  std::string returnType = variantInfo->getReturnTypeName(type);
444  CppMethodPtr getMethod = targetClass->addPublicMethod(
445  boost::str(boost::format("%s get%s() const") % returnType % name), doc);
446  getMethod->addLine(boost::format("return parent->%s< %s>(\"%s\");") % parentGetMethodName %
447  dataType % name);
448  }
449  // Single Container, i.e. vector<int>, generated output:
450  // [std-container]<[innerReturnType]> get[Name]() { return parent->[getInput|getLocal|getOutput]<[Variant-ContainerType]>("[Name]")->[variant-container-specific-to-std-container-method]<[innerDataType]>(); }
451  // all containers are suppoted, as long as these containers are: "::armarx::StringValueMapBase" OR "::armarx::SingleTypeVariantListBase"
452  // NOTE: innerDataType == innerReturnType for basic types, innerReturnType = innerDataType + "Ptr" for non basic types, see variantInfo->getDataTypeName and variantInfo->getReturnTypeName
453  // ALSO NOTE: the + "Ptr" is hardcoded, so if the convention of a typedef for a ice-pointer is not met invalid code is generated.
454  // examples:
455  // std::vector<int> getMyParam1() { return parent->getInput< ::armarx::SingleTypeVariantList>()->toStdVector<int>(); }
456  else if (!containerInfo->subType->subType)
457  {
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";
464 
465  if (containerInfo->typeId == "::armarx::StringValueMapBase")
466  {
467  containerType = "::armarx::StringValueMap";
468  toStdContainerMethodName = "toStdMap";
469  returnType = fmt("std::map<std::string, %s>", innerReturnType);
470  }
471  else if (containerInfo->typeId == "::armarx::SingleTypeVariantListBase")
472  {
473  containerType = "::armarx::SingleTypeVariantList";
474  toStdContainerMethodName = "toStdVector";
475  returnType = fmt("std::vector< %s>", innerReturnType);
476  }
477 
478  CppMethodPtr getMethod = targetClass->addPublicMethod(
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);
483  }
484  // 2 or more level container: WHY U EVEN USING THIS?
485  // but it is supported nonetheless
486  else
487  {
488  std::string innerDataType = "NOT_FOUND";
489  std::string innerReturnType = "NOT_FOUND";
490 
491  if (containerInfo->subType->typeId == "::armarx::StringValueMapBase")
492  {
493  innerDataType = "::armarx::StringValueMapPtr";
494  innerReturnType = "::armarx::StringValueMapPtr";
495  }
496  else if (containerInfo->subType->typeId == "::armarx::SingleTypeVariantListBase")
497  {
498  innerDataType = "::armarx::SingleTypeVariantListPtr";
499  innerReturnType = "::armarx::SingleTypeVariantListPtr";
500  }
501 
502  std::string containerType = "NOT_FOUND";
503  std::string toStdContainerMethodName = "NOT_FOUND";
504  std::string returnType = "NOT_FOUND";
505 
506  if (containerInfo->typeId == "::armarx::StringValueMapBase")
507  {
508  containerType = "::armarx::StringValueMap";
509  toStdContainerMethodName = "toContainerStdMap";
510  returnType = fmt("std::map<std::string, %s>", innerReturnType);
511  }
512  else if (containerInfo->typeId == "::armarx::SingleTypeVariantListBase")
513  {
514  containerType = "::armarx::SingleTypeVariantList";
515  toStdContainerMethodName = "toContainerStdVector";
516  returnType = fmt("std::vector< %s>", innerReturnType);
517  }
518 
519  CppMethodPtr getMethod = targetClass->addPublicMethod(
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);
524  }
525 }
526 
527 void
528 XmlStateBaseClassGenerator::AddIsSet(RapidXmlReaderNode node,
529  CppClassPtr targetClass,
530  VariantInfoPtr variantInfo,
531  const std::string& parentTestParamMethodName)
532 {
533  std::string name = node.attribute_value("name");
534 
535  CppMethodPtr getMethod =
536  targetClass->addPublicMethod(boost::str(boost::format("bool is%sSet() const") % name));
537  getMethod->addLine(boost::format("return parent->%s(\"%s\");") % parentTestParamMethodName %
538  name);
539 }
540 
541 void
542 XmlStateBaseClassGenerator::AddSet(RapidXmlReaderNode node,
543  CppClassPtr targetClass,
544  VariantInfoPtr variantInfo,
545  const std::string& parentSetMethodName)
546 {
547  std::string name = node.attribute_value("name");
548  std::string type = node.attribute_value("type");
549  std::string doc = node.first_node_value_or_default("Description", "");
550  ContainerTypePtr containerInfo = VariantContainerType::FromString(type);
551 
552  // No Container
553  if (!containerInfo->subType)
554  {
555  // generate for non-pointer
556  std::string dataType = variantInfo->getDataTypeName(containerInfo->typeId);
557  CppMethodPtr setMethod = targetClass->addPublicMethod(
558  boost::str(boost::format("void set%s(const %s & value)") % name % dataType), doc);
559  setMethod->addLine(boost::format("parent->%s(\"%s\", value);") % parentSetMethodName %
560  name);
561 
562  if (!variantInfo->isBasic(containerInfo->typeId))
563  {
564  // generate for pointer if type is non-basic
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);
570  }
571  }
572  else if (!containerInfo->subType->subType)
573  {
574  //std::string innerDataType = variantInfo->getDataTypeName(containerInfo->subType->typeId);
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";
579 
580  if (containerInfo->typeId == "::armarx::StringValueMapBase")
581  {
582  containerType = "::armarx::StringValueMapPtr";
583  fromStdContainerMethod =
584  fmt("::armarx::StringValueMap::FromStdMap< %s>", innerParamType);
585  paramType = fmt("std::map<std::string, %s>", innerParamType);
586  }
587  else if (containerInfo->typeId == "::armarx::SingleTypeVariantListBase")
588  {
589  containerType = "::armarx::SingleTypeVariantListPtr";
590  fromStdContainerMethod =
591  fmt("::armarx::SingleTypeVariantList::FromStdVector< %s>", innerParamType);
592  paramType = fmt("std::vector< %s>", innerParamType);
593  }
594 
595  CppMethodPtr setMethod = targetClass->addPublicMethod(
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 %
600  name);
601  }
602  else
603  {
604  //std::string innerDataType = "NOT_FOUND";
605  std::string innerParamType = "NOT_FOUND";
606 
607  if (containerInfo->subType->typeId == "::armarx::StringValueMapBase")
608  {
609  //innerDataType = "::armarx::StringValueMapPtr";
610  innerParamType = "::armarx::StringValueMapPtr";
611  }
612  else if (containerInfo->subType->typeId == "::armarx::SingleTypeVariantListBase")
613  {
614  //innerDataType = "::armarx::SingleTypeVariantListPtr";
615  innerParamType = "::armarx::SingleTypeVariantListPtr";
616  }
617 
618  std::string fromStdContainerMethod = "NOT_FOUND";
619  std::string paramType = "NOT_FOUND";
620  std::string containerType = "NOT_FOUND";
621 
622  if (containerInfo->typeId == "::armarx::StringValueMapBase")
623  {
624  containerType = "::armarx::StringValueMapPtr";
625  fromStdContainerMethod =
626  fmt("::armarx::StringValueMap::FromContainerStdMap< %s>", innerParamType);
627  paramType = fmt("std::map<std::string, %s>", innerParamType);
628  }
629  else if (containerInfo->typeId == "::armarx::SingleTypeVariantListBase")
630  {
631  containerType = "::armarx::SingleTypeVariantListPtr";
632  fromStdContainerMethod =
633  fmt("::armarx::SingleTypeVariantList::FromContainerStdVector< %s>", innerParamType);
634  paramType = fmt("std::vector< %s>", innerParamType);
635  }
636 
637  CppMethodPtr setMethod = targetClass->addPublicMethod(
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 %
642  name);
643  }
644 }
645 
646 void
647 XmlStateBaseClassGenerator::AddTransitionCodeFunctions(RapidXmlReaderNode stateNode,
648  CppClassPtr targetClass)
649 {
650  auto transitionsNode = stateNode.first_node("Transitions");
651  bool foundUserCodeTransition = false;
652 
653  // TODO obtain this mapping from somewhere else
654  const std::unordered_map<std::string, std::string> packageIncludePaths{
655  {"armar6_rt", "armar6/rt"}, {"armar6_skills", "armar6/skills"},
656  // {"armar6_rt", "armar6/rt"},
657  };
658 
659  const auto getPackageIncludePath = [&](const std::string& packageName) -> std::string
660  {
661  if (packageIncludePaths.count(packageName))
662  {
663  return packageIncludePaths.at(packageName);
664  }
665 
666  return packageName;
667  };
668 
669 
670  for (RapidXmlReaderNode& tNode : transitionsNode.nodes("Transition"))
671  {
672  bool userCode = tNode.attribute_as_optional_bool("transitionCodeEnabled", "1", "0", false);
673  if (userCode)
674  {
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");
683 
684  if (!toPackage.empty() && !toGroup.empty() && !toClass.empty())
685  {
686  const std::string packageIncludePath = getPackageIncludePath(toPackage);
687  targetClass->addInclude(fmt(
688  "<%s/statecharts/%s/%s.generated.h>", packageIncludePath, toGroup, toClass));
689  }
690  if (!fromPackage.empty() && !fromGroup.empty() && !fromClass.empty())
691  {
692  const std::string packageIncludePath = getPackageIncludePath(fromPackage);
693  targetClass->addInclude(fmt("<%s/statecharts/%s/%s.generated.h>",
694  packageIncludePath,
695  fromGroup,
696  fromClass));
697  }
698  auto method = targetClass->addPublicMethod(boost::str(
699  boost::format(
700  "virtual void transition%sFrom%s(%s::%sIn &next, const %s::%sOut &prev) = 0;") %
701  eventName % fromStateInstanceName % toGroup % toClass % fromGroup % fromClass));
702  foundUserCodeTransition = true;
703  }
704  }
705 
706  if (foundUserCodeTransition)
707  {
708  std::string currentStateName = stateNode.attribute_value("name");
709  CppMethodPtr method = targetClass->addPublicMethod("void defineSubstates()");
710  method->addLine("XMLStateTemplate < StateType >::defineSubstates();");
711  method->addLine("TransitionIceBase t;");
712  for (RapidXmlReaderNode& tNode : transitionsNode.nodes("Transition"))
713  {
714  bool userCode =
715  tNode.attribute_as_optional_bool("transitionCodeEnabled", "1", "0", false);
716  if (userCode)
717  {
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)",
727  eventName,
728  fromStateInstanceName));
729  helperMethod->addLine(
730  boost::format("%s::%sIn input(dynamic_cast<State*>(nextState.get()));") %
731  toGroup % toClass);
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);
743 
744  method->addLine(fmt("if (StateController::findTransition(\"%s\", \"%s\", t))",
745  eventName,
746  fromStateInstanceName));
747  method->addLine(
748  fmt("\tthis->addTransitionFunction(t, "
749  "std::bind(&%sGeneratedBase<StateType>::_transition%sFrom%s, this, "
750  "std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));",
751  currentStateName,
752  eventName,
753  fromStateInstanceName));
754  }
755  }
756  }
757 }
758 
759 std::string
760 XmlStateBaseClassGenerator::fmt(const std::string& fmt, const std::string& arg1)
761 {
762  return str(boost::format(fmt) % arg1);
763 }
764 
765 std::string
766 XmlStateBaseClassGenerator::fmt(const std::string& fmt,
767  const std::string& arg1,
768  const std::string& arg2)
769 {
770  return str(boost::format(fmt) % arg1 % arg2);
771 }
772 
773 std::string
774 XmlStateBaseClassGenerator::fmt(const std::string& fmt,
775  const std::string& arg1,
776  const std::string& arg2,
777  const std::string& arg3)
778 {
779  return str(boost::format(fmt) % arg1 % arg2 % arg3);
780 }
781 
782 std::string
783 XmlStateBaseClassGenerator::generateDocString(RapidXmlReaderNode stateNode,
784  const std::string& packageName,
785  const std::vector<std::string>& namespaces,
786  bool isPublicState)
787 {
788  std::string className = stateNode.attribute_value("name");
789  auto docNode = stateNode.first_node("Description");
790  std::string docString;
791  docString += "@class " + className + "GeneratedBase\n";
792 
793  if (namespaces.size() != 0)
794  {
795  docString += "@ingroup " + packageName + "-" + *namespaces.rbegin() +
796  (isPublicState ? "" : "-Substates") + "\n";
797  }
798 
799  if (docNode.is_valid())
800  {
801  docString += docNode.value();
802  }
803 
804  docString += generateParameterTableString(stateNode);
805 
806  auto graphString = generateDotGraphString(stateNode);
807 
808  if (!graphString.empty())
809  {
810  docString += "\n\n" + graphString;
811  }
812 
813  return docString;
814 }
815 
816 std::string
817 XmlStateBaseClassGenerator::generateParameterTableString(RapidXmlReaderNode stateNode)
818 {
819  std::string result;
820 
821 
822  /**
823  for (RapidXmlReaderNode inputParameter : stateNode.nodes("InputParameters", "Parameter"))
824  {
825  result +=
826  }
827 
828 
829 
830  auto inputParameters = stateNode.first_node("InputParameters");
831  if(inputParameters.first_node("Parameter").is_valid())
832  {
833  result = "\n \n Input parameters: \n";
834  result += "name | type | description \n";
835  for (RapidXmlReaderNode curParameterNode = inputParameters.first_node();
836  curParameterNode.is_valid();
837  curParameterNode = curParameterNode.next_sibling("Parameter"))
838  {
839  result
840  }
841 
842  }
843  */
844 
845 
846  return result;
847 }
848 
849 std::string
850 XmlStateBaseClassGenerator::generateDotGraphString(RapidXmlReaderNode stateNode)
851 {
852  std::string result;
853  auto transitions = stateNode.first_node("Transitions");
854 
855  if (transitions.first_node("Transition").is_valid())
856  {
857 
858  result = "\n \nTransitiongraph of the substates:\n";
859  result += "@dot\n\tdigraph States {\n";
860 
861  for (RapidXmlReaderNode curTransitionNode = transitions.first_node("Transition");
862  curTransitionNode.is_valid();
863  curTransitionNode = curTransitionNode.next_sibling("Transition"))
864  {
865  if (curTransitionNode.has_attribute("from") && curTransitionNode.has_attribute("to") &&
866  curTransitionNode.has_attribute("eventName"))
867  {
868  result += "\t\t" + curTransitionNode.attribute_value("from") + "->" +
869  curTransitionNode.attribute_value("to") + "[ label=\"" +
870  curTransitionNode.attribute_value("eventName") + "\" ];\n";
871  }
872  }
873 
874  result += "}\n@enddot";
875  return result;
876  }
877 
878  return "";
879 }
880 
881 DoxDocPtr
882 XmlStateBaseClassGenerator::generateDoxDoc(RapidXmlReaderNode stateNode,
883  const std::string& packageName,
884  std::vector<std::string>& namespaces,
885  bool isPublicState,
886  VariantInfoPtr variantInfo,
887  Ice::CommunicatorPtr communicator)
888 {
889  std::string className = stateNode.attribute_value("name");
890  DoxDocPtr doc(new DoxDoc());
891 
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));
894 
895  if (!isPublicState)
896  {
897  doxGroupName += "-Substates";
898  }
899 
900  doc->addLine(fmt("@ingroup %s\n", doxGroupName));
901 
902  std::string doxBrief;
903  std::string doxDescription = stateNode.first_node_value_or_default("Description", "");
904 
905  if (doxDescription.size() > 0)
906  {
907  std::vector<std::string> descLines = simox::alg::split(doxDescription, ".");
908  doxBrief = descLines[0];
909  doc->addLine(fmt("@brief %s\n", doxBrief));
910  }
911  else
912  {
913  doxBrief = fmt("@brief Brief description of state %s\n", className);
914  doc->addLine(doxBrief);
915  }
916 
917 
918  // input parameters
919  RapidXmlReaderNode inputParameters = stateNode.first_node("InputParameters");
920 
921  if (inputParameters.first_node("Parameter").is_valid())
922  {
923  doc->addLine("Input parameters:");
924  doc->addParameterTable(inputParameters, variantInfo, communicator);
925  }
926 
927  // local parameters
928  RapidXmlReaderNode localParameters = stateNode.first_node("LocalParameters");
929 
930  if (localParameters.first_node("Parameter").is_valid())
931  {
932  doc->addLine("Local parameters:");
933  doc->addParameterTable(localParameters, variantInfo, communicator);
934  }
935 
936  // output parameters
937  RapidXmlReaderNode outputParameters = stateNode.first_node("OutputParameters");
938 
939  if (outputParameters.first_node("Parameter").is_valid())
940  {
941  doc->addLine("Output parameters");
942  doc->addParameterTable(outputParameters, variantInfo, communicator);
943  }
944 
945  RapidXmlReaderNode transitions = stateNode.first_node("Transitions");
946 
947  if (transitions.first_node("Transition").is_valid())
948  {
949  doc->addLine("Transition graph");
950  doc->addTransitionGraph(transitions);
951  }
952 
953 
954  doc->addLine(fmt("@class %sGeneratedBase", className));
955 
956  if (namespaces.size() != 0)
957  {
958  //doc->addLine(fmt("@ingroup %s-%s%s", packageName, namespaces.at(namespaces.size() - 1), isPublicState ? "" : "-Substates"));
959  //doc->addLine(fmt("@ingroup %s", doxGroupName));
960  doc->addLine(fmt("@ingroup %s-%s-State", packageName, className));
961  }
962 
963  doc->addLine(
964  fmt("For a documentation of this state see @ref %s-%s-State", packageName, className));
965 
966  if (doxBrief.size() > 0)
967  {
968  doc->addLine(doxBrief);
969  }
970 
971  doc->addLine(doxDescription.substr(0, 80));
972 
973 
974  return doc;
975 }
armarx::RapidXmlReaderPtr
std::shared_ptr< RapidXmlReader > RapidXmlReaderPtr
Definition: RapidXmlReader.h:67
str
std::string str(const T &t)
Definition: UserAssistedSegmenterGuiWidgetController.cpp:43
armarx::CppCtorPtr
std::shared_ptr< CppCtor > CppCtorPtr
Definition: CppCtor.h:31
XmlStateBaseClassGenerator.h
VariantContainer.h
armarx::CppClassPtr
std::shared_ptr< CppClass > CppClassPtr
Definition: CppClass.h:35
armarx::RapidXmlReaderNode::attribute_as_optional_bool
bool attribute_as_optional_bool(const char *name, const std::string &trueValue, const std::string &falseValue, bool defaultValue) const
Definition: RapidXmlReader.h:299
armarx::RapidXmlReaderNode::attribute_value
std::string attribute_value(const char *attrName) const
Definition: RapidXmlReader.h:230
armarx::DoxDocPtr
std::shared_ptr< DoxDoc > DoxDocPtr
Definition: DoxDoc.h:40
armarx::XmlStateBaseClassGenerator::GetUsedInnerNonBasicVariantTypes
static std::set< std::string > GetUsedInnerNonBasicVariantTypes(RapidXmlReaderNode stateNode, VariantInfoPtr variantInfo)
Definition: XmlStateBaseClassGenerator.cpp:66
armarx::CppFieldPtr
std::shared_ptr< CppField > CppFieldPtr
Definition: CppField.h:33
IceInternal::Handle<::Ice::Communicator >
armarx::ctrlutil::a
double a(double t, double a0, double j)
Definition: CtrlUtil.h:45
armarx::CppField::getName
std::string getName() const
Definition: CppField.cpp:46
armarx::VariantInfo::ProxyEntryPtr
std::shared_ptr< ProxyEntry > ProxyEntryPtr
Definition: VariantInfo.h:76
armarx::XmlStateBaseClassGenerator::XmlStateBaseClassGenerator
XmlStateBaseClassGenerator()
Definition: XmlStateBaseClassGenerator.cpp:40
armarx::CppClass
Definition: CppClass.h:37
armarx::CppMethodPtr
std::shared_ptr< CppMethod > CppMethodPtr
Definition: CppMethod.h:31
armarx::RapidXmlReaderNode
Definition: RapidXmlReader.h:69
ARMARX_WARNING_S
#define ARMARX_WARNING_S
Definition: Logging.h:213
armarx::CppClass::WriteCpp
static void WriteCpp(const std::vector< CppClassPtr > &classes, const CppWriterPtr &writer)
Definition: CppClass.cpp:54
armarx::RapidXmlReaderNode::value
std::string value() const
Definition: RapidXmlReader.h:365
CMakePackageFinder.h
armarx::CppWriter
Definition: CppWriter.h:37
armarx::XmlStateBaseClassGenerator::GetIncludesForInnerNonBasicVariantTypes
static std::set< std::string > GetIncludesForInnerNonBasicVariantTypes(RapidXmlReaderNode stateNode, VariantInfoPtr variantInfo)
Definition: XmlStateBaseClassGenerator.cpp:91
armarx::RapidXmlReaderNode::first_node_value_or_default
std::string first_node_value_or_default(const char *name, const std::string &defaultValue) const
Definition: RapidXmlReader.h:436
armarx::VariantInfoPtr
std::shared_ptr< VariantInfo > VariantInfoPtr
Definition: VariantInfo.h:39
armarx::RapidXmlReaderNode::nodes
std::vector< RapidXmlReaderNode > nodes(const char *name=nullptr) const
Definition: RapidXmlReader.h:181
armarx::RapidXmlReaderNode::is_valid
bool is_valid() const
Definition: RapidXmlReader.h:457
armarx::CppField
Definition: CppField.h:35
armarx::CppWriterPtr
std::shared_ptr< CppWriter > CppWriterPtr
Definition: CppWriter.h:35
armarx::CppMethod
Definition: CppMethod.h:33
Logging.h
ArmarXDataPath.h
armarx::RapidXmlReaderNode::first_node
RapidXmlReaderNode first_node(const char *name=nullptr) const
Definition: RapidXmlReader.h:156
armarx::DoxDoc
Definition: DoxDoc.h:42
armarx::VariantInfo::LibEntryPtr
std::shared_ptr< LibEntry > LibEntryPtr
Definition: VariantInfo.h:211
armarx::VariantContainerType::FromString
static ContainerTypePtr FromString(const std::string &typeStr)
Definition: VariantContainer.cpp:281
armarx
This file offers overloads of toIce() and fromIce() functions for STL container types.
Definition: ArmarXTimeserver.cpp:27
armarx::split
std::vector< std::string > split(const std::string &source, const std::string &splitBy, bool trimElements=false, bool removeEmptyElements=false)
Definition: StringHelpers.cpp:38
armarx::XmlStateBaseClassGenerator::GenerateCpp
static std::string GenerateCpp(std::vector< std::string > namespaces, RapidXmlReaderPtr reader, const std::vector< std::string > &proxies, bool contextGenerationEnabled, std::string groupName, VariantInfoPtr variantInfo)
Definition: XmlStateBaseClassGenerator.cpp:45