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 <SimoxUtility/algorithm/string/string_tools.h>
29 #include <boost/format.hpp>
30 
31 #include <filesystem>
32 
36 
37 using namespace armarx;
38 
40 {
41 
42 }
43 
44 
45 std::string XmlStateBaseClassGenerator::GenerateCpp(std::vector<std::string> namespaces, RapidXmlReaderPtr reader, const std::vector<std::string>& proxies, bool contextGenerationEnabled, std::string groupName, VariantInfoPtr variantInfo)
46 {
47  auto cppClasses = BuildClass(namespaces, reader->getRoot("State"), proxies, contextGenerationEnabled, groupName, variantInfo);
48 
49  CppWriterPtr writer(new CppWriter(true));
50  writer->body.line();
51  CppClass::WriteCpp(cppClasses, writer);
52  return writer->getString();
53 }
54 
56 {
57  std::set<std::string> usedInnerNonBasicVariantDataTypes;
58 
59  for (std::string typeName : GetUsedVariantTypes(stateNode))
60  {
61  ContainerTypePtr type = VariantContainerType::FromString(typeName);
62 
63  // Find the inner type, all outer types are containers. If there is no container type->subType is null
64  while (type->subType)
65  {
66  type = type->subType;
67  }
68 
69  if (!variantInfo->isBasic(type->typeId))
70  {
71  usedInnerNonBasicVariantDataTypes.insert(type->typeId);
72  }
73  }
74 
75  return usedInnerNonBasicVariantDataTypes;
76 }
77 
79 {
80  std::set<std::string> includePaths;
81 
82  for (std::string typeName : GetUsedVariantTypes(stateNode))
83  {
84  ContainerTypePtr type = VariantContainerType::FromString(typeName);
85 
86  // Find the inner type, all outer types are containers. If there is no container type->subType is null
87  while (type->subType)
88  {
89  type = type->subType;
90  }
91 
92  if (!variantInfo->isBasic(type->typeId))
93  {
94  auto libEntry = variantInfo->findLibByVariant(type->typeId);
95  if (libEntry)
96  {
97  auto includes = libEntry->getVariantIncludes(type->typeId);
98  includePaths.insert(includes.begin(), includes.end());
99  }
100  }
101  }
102 
103  return includePaths;
104 }
105 
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)
107 {
108  std::vector<CppClassPtr> classes;
109  std::string className = stateNode.attribute_value("name");
110  std::string baseClassName = className + "GeneratedBase";
111 
112  for (std::string& ns : namespaces)
113  {
114  ns = simox::alg::replace_all(ns, "-", "_");
115  }
116 
117  CppClassPtr cppClass(new CppClass(namespaces, baseClassName, "template<typename StateType>"));
118 
119  // auto docString = generateDocString(stateNode, packageName, namespaces, isPublicState);
120  // cppClass->addClassDoc(docString);
121  // DoxDocPtr doxDoc = generateDoxDoc(stateNode, packageName, namespaces, isPublicState, variantInfo, communicator);
122  // cppClass->addClassDoc(doxDoc);
123 
124 
125  CppClassPtr inClass(new CppClass(namespaces, className + "In"));
126  CppClassPtr localClass(new CppClass(namespaces, className + "Local"));
127  CppClassPtr outClass(new CppClass(namespaces, className + "Out"));
128 
129  inClass->addInclude("<ArmarXCore/statechart/xmlstates/XMLState.h>");
130 
131  if (contextGenerationEnabled)
132  {
133  /*std::stringstream ssNesting;
134  for(int i = 0; i < nestingLevel; i++)
135  {
136  ssNesting << "../";
137  }
138  cppClass->addInclude(fmt("\"%s%sStatechartContext.generated.h\"", ssNesting.str(), groupName));*/
139  cppClass->addInclude(fmt("\"%sStatechartContextBase.generated.h\"", groupName));
140  }
141 
142  std::set<VariantInfo::LibEntryPtr> usedLibs;
143 
144  for (std::string typeName : GetUsedVariantTypes(stateNode))
145  {
146  ContainerTypePtr type = VariantContainerType::FromString(typeName);
147 
148  // Find the inner type, all outer types are containers. If there is no container type->subType is null
149  while (type->subType)
150  {
151  type = type->subType;
152  }
153 
154  VariantInfo::LibEntryPtr lib = variantInfo->findLibByVariant(type->typeId);
155 
156  if (lib)
157  {
158  usedLibs.insert(lib);
159  }
160  else
161  {
162  inClass->addInclude("MISSING INCLUDE FOR " + type->typeId);
163  }
164  }
165  std::set<std::string> usedInnerNonBasicVariantDataTypes = GetUsedInnerNonBasicVariantTypes(stateNode, variantInfo);
166  std::set<std::string> usedInnerNonBasicVariantDataImplementationTypes;
167  for (auto& basicType : usedInnerNonBasicVariantDataTypes)
168  {
169  usedInnerNonBasicVariantDataImplementationTypes.insert(variantInfo->getDataTypeName(basicType));
170  }
171 
172  std::set<std::string> variantIncludes = GetIncludesForInnerNonBasicVariantTypes(stateNode, variantInfo);
173  for (auto& include : variantIncludes)
174  {
175  cppClass->addInclude(fmt("<%s>", include));
176  }
177 
178  std::vector<VariantInfo::LibEntryPtr> usedLibsVector(usedLibs.begin(), usedLibs.end());
179  std::sort(usedLibsVector.begin(), usedLibsVector.end(), [](VariantInfo::LibEntryPtr a, VariantInfo::LibEntryPtr b)
180  {
181  return a->getName().compare(b->getName()) < 0;
182  });
183 
184  std::vector<std::string> usedInnerNonBasicVariantDataTypesVector(usedInnerNonBasicVariantDataImplementationTypes.begin(), usedInnerNonBasicVariantDataImplementationTypes.end());
185  std::sort(usedInnerNonBasicVariantDataTypesVector.begin(), usedInnerNonBasicVariantDataTypesVector.end(), [](std::string a, std::string b)
186  {
187  return a.compare(b) > 0;
188  });
189 
190  inClass->addInclude("<ArmarXCore/core/system/FactoryCollectionBase.h>");
191 
192  // for (VariantInfo::LibEntryPtr lib : usedLibsVector)
193  // {
194  // for (std::string include : lib->getFactoryIncludes())
195  // {
196  // cppClass->addInclude(fmt("<%s>", include));
197  // }
198  // }
199 
200  cppClass->addInherit("virtual public XMLStateTemplate < StateType >");
201  cppClass->addInherit("public XMLStateFactoryBase");
202 
203  CppFieldPtr in = CppFieldPtr(new CppField{inClass->getName(), "in"});
204  cppClass->addProtectedField(in);
205 
206  CppFieldPtr local = CppFieldPtr(new CppField{localClass->getName(), "local"});
207  cppClass->addProtectedField(local);
208 
209  CppFieldPtr out = CppFieldPtr(new CppField{outClass->getName(), "out"});
210  cppClass->addProtectedField(out);
211 
212  CppFieldPtr p = CppFieldPtr(new CppField{"State*", "parent"});
213  inClass->addPrivateField(p);
214  localClass->addPrivateField(p);
215  outClass->addPrivateField(p);
216 
217  inClass->addCtor(("State *parent"))->addInitListEntry("parent", "parent");
218  localClass->addCtor(("State *parent"))->addInitListEntry("parent", "parent");
219  outClass->addCtor(("State *parent"))->addInitListEntry("parent", "parent");
220 
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()));
227 
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()));
239 
240  std::set<std::string> events;
241  for (RapidXmlReaderNode n : stateNode.nodes("Events", "Event"))
242  {
243  events.insert(n.attribute_value("name"));
244  }
245  for (RapidXmlReaderNode n : stateNode.nodes("Substates", "EndState"))
246  {
247  events.insert(n.attribute_value("name"));
248  }
249 
250  for (const std::string& name : events)
251  {
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));
258  }
259 
260  for (RapidXmlReaderNode p : stateNode.nodes("InputParameters", "Parameter"))
261  {
262  AddGet(p, inClass, variantInfo, "getInput");
263  AddSet(p, inClass, variantInfo, "setInput");
264  AddIsSet(p, inClass, variantInfo, "isInputParameterSet");
265  }
266 
267  for (RapidXmlReaderNode p : stateNode.nodes("LocalParameters", "Parameter"))
268  {
269  AddGet(p, localClass, variantInfo, "getLocal");
270  AddSet(p, localClass, variantInfo, "setLocal");
271  AddIsSet(p, localClass, variantInfo, "isLocalParameterSet");
272  }
273 
274  for (RapidXmlReaderNode p : stateNode.nodes("OutputParameters", "Parameter"))
275  {
276  AddGet(p, outClass, variantInfo, "getOutput");
277  AddSet(p, outClass, variantInfo, "setOutput");
278  AddIsSet(p, outClass, variantInfo, "isOutputParameterSet");
279  }
280 
281  if (contextGenerationEnabled)
282  {
283  for (std::string proxyId : proxies)
284  {
285  VariantInfo::ProxyEntryPtr p = variantInfo->getProxyEntry(proxyId);
286 
287  if (p)
288  {
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()));
293  // std::string include = fmt("<%s>", p->getIncludePath());
294 
295  // if (!cppClass->hasInclude(include))
296  // {
297  // cppClass->addInclude(include);
298  // }
299 
300  for (std::pair<std::string, std::string> method : p->getStateMethods())
301  {
302  cppClass->addPublicMethod(method.first)->addLine(simox::alg::replace_all(method.second, "%getContext%", fmt("StateBase::getContext<%sStatechartContextBase>()", groupName)));
303  }
304  }
305  else
306  {
307  ARMARX_WARNING_S << "Cannot find proxy info for " << proxyId << " for state " << className << " in group " << groupName;
308  ARMARX_WARNING_S << "VariantInfo: " << variantInfo->getDebugInfo();
309  }
310  }
311  }
312 
313 
314  CppMethodPtr getName(new CppMethod("static std::string GetName()"));
315  getName->addLine(fmt("return \"%s\";", className));
316  cppClass->addPublicMethod(getName);
317 
318  CppMethodPtr cloneFunc(new CppMethod("StateBasePtr clone() const override"));
319  cloneFunc->addLine("StatePtr result = new StateType(*dynamic_cast<const StateType*>(this));");
320  cloneFunc->addLine("return result;");
321  cppClass->addPublicMethod(cloneFunc);
322 
323  // CppMethodPtr createEmptyCopyFunc(new CppMethod("StateBasePtr createEmptyCopy() const override"));
324  // createEmptyCopyFunc->addLine("return new StateType();");
325  // cppClass->addMethod(createEmptyCopyFunc);
326 
327  if (usedInnerNonBasicVariantDataTypesVector.size() > 0)
328  {
329  // 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).
330  CppMethodPtr forceLibLoading(new CppMethod("void __attribute__((used)) __forceLibLoading()"));
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.");
333 
334  int typeNr = 1;
335 
336  for (std::string innerNonBasicVariantDataType : usedInnerNonBasicVariantDataTypesVector)
337  {
338  forceLibLoading->addLine(fmt("armarx::GenericFactory< %s, %s> ().create(%s::ice_staticId());", innerNonBasicVariantDataType, innerNonBasicVariantDataType, innerNonBasicVariantDataType));
339 
340  typeNr++;
341  }
342 
343  cppClass->addPublicMethod(forceLibLoading);
344  }
345 
346  AddTransitionCodeFunctions(stateNode, cppClass);
347 
348  /*CppMethodPtr createInstance(new CppMethod("static XMLStateFactoryBasePtr CreateInstance(XMLStateConstructorParams stateData)"));
349  createInstance->addLine(fmt("return XMLStateFactoryBasePtr(new %s(stateData));", className));
350  cppClass->addMethod(createInstance);*/
351  classes.push_back(inClass);
352  classes.push_back(localClass);
353  classes.push_back(outClass);
354  classes.push_back(cppClass);
355  return classes;
356 }
357 
358 std::set<std::string> XmlStateBaseClassGenerator::GetUsedVariantTypes(RapidXmlReaderNode stateNode)
359 {
360  std::set<std::string> usedVariantTypes;
361 
362  for (RapidXmlReaderNode p : stateNode.nodes("InputParameters", "Parameter"))
363  {
364  std::string type = p.attribute_value("type");
365  usedVariantTypes.insert(type);
366  }
367 
368  for (RapidXmlReaderNode p : stateNode.nodes("LocalParameters", "Parameter"))
369  {
370  std::string type = p.attribute_value("type");
371  usedVariantTypes.insert(type);
372  }
373 
374  for (RapidXmlReaderNode p : stateNode.nodes("OutputParameters", "Parameter"))
375  {
376  std::string type = p.attribute_value("type");
377  usedVariantTypes.insert(type);
378  }
379 
380  return usedVariantTypes;
381 }
382 
383 
384 void XmlStateBaseClassGenerator::AddGet(RapidXmlReaderNode node, CppClassPtr targetClass, VariantInfoPtr variantInfo, const std::string& parentGetMethodName)
385 {
386  std::string name = node.attribute_value("name");
387  std::string type = node.attribute_value("type");
388  std::string doc = node.first_node_value_or_default("Description", "");
389  ContainerTypePtr containerInfo = VariantContainerType::FromString(type);
390 
391  // No Container, generated output:
392  // [returnType] get[Name]() { return parent->[getInput|getLocal|getOutput]<[dataType]>("[Name]"); }
393  if (!containerInfo->subType)
394  {
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);
399  }
400  // Single Container, i.e. vector<int>, generated output:
401  // [std-container]<[innerReturnType]> get[Name]() { return parent->[getInput|getLocal|getOutput]<[Variant-ContainerType]>("[Name]")->[variant-container-specific-to-std-container-method]<[innerDataType]>(); }
402  // all containers are suppoted, as long as these containers are: "::armarx::StringValueMapBase" OR "::armarx::SingleTypeVariantListBase"
403  // NOTE: innerDataType == innerReturnType for basic types, innerReturnType = innerDataType + "Ptr" for non basic types, see variantInfo->getDataTypeName and variantInfo->getReturnTypeName
404  // ALSO NOTE: the + "Ptr" is hardcoded, so if the convention of a typedef for a ice-pointer is not met invalid code is generated.
405  // examples:
406  // std::vector<int> getMyParam1() { return parent->getInput< ::armarx::SingleTypeVariantList>()->toStdVector<int>(); }
407  else if (!containerInfo->subType->subType)
408  {
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";
414 
415  if (containerInfo->typeId == "::armarx::StringValueMapBase")
416  {
417  containerType = "::armarx::StringValueMap";
418  toStdContainerMethodName = "toStdMap";
419  returnType = fmt("std::map<std::string, %s>", innerReturnType);
420  }
421  else if (containerInfo->typeId == "::armarx::SingleTypeVariantListBase")
422  {
423  containerType = "::armarx::SingleTypeVariantList";
424  toStdContainerMethodName = "toStdVector";
425  returnType = fmt("std::vector< %s>", innerReturnType);
426  }
427 
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);
430 
431  }
432  // 2 or more level container: WHY U EVEN USING THIS?
433  // but it is supported nonetheless
434  else
435  {
436  std::string innerDataType = "NOT_FOUND";
437  std::string innerReturnType = "NOT_FOUND";
438 
439  if (containerInfo->subType->typeId == "::armarx::StringValueMapBase")
440  {
441  innerDataType = "::armarx::StringValueMapPtr";
442  innerReturnType = "::armarx::StringValueMapPtr";
443  }
444  else if (containerInfo->subType->typeId == "::armarx::SingleTypeVariantListBase")
445  {
446  innerDataType = "::armarx::SingleTypeVariantListPtr";
447  innerReturnType = "::armarx::SingleTypeVariantListPtr";
448  }
449 
450  std::string containerType = "NOT_FOUND";
451  std::string toStdContainerMethodName = "NOT_FOUND";
452  std::string returnType = "NOT_FOUND";
453 
454  if (containerInfo->typeId == "::armarx::StringValueMapBase")
455  {
456  containerType = "::armarx::StringValueMap";
457  toStdContainerMethodName = "toContainerStdMap";
458  returnType = fmt("std::map<std::string, %s>", innerReturnType);
459  }
460  else if (containerInfo->typeId == "::armarx::SingleTypeVariantListBase")
461  {
462  containerType = "::armarx::SingleTypeVariantList";
463  toStdContainerMethodName = "toContainerStdVector";
464  returnType = fmt("std::vector< %s>", innerReturnType);
465  }
466 
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);
469  }
470 }
471 
472 void XmlStateBaseClassGenerator::AddIsSet(RapidXmlReaderNode node, CppClassPtr targetClass, VariantInfoPtr variantInfo, const std::string& parentTestParamMethodName)
473 {
474  std::string name = node.attribute_value("name");
475 
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);
478 }
479 
480 void XmlStateBaseClassGenerator::AddSet(RapidXmlReaderNode node, CppClassPtr targetClass, VariantInfoPtr variantInfo, const std::string& parentSetMethodName)
481 {
482  std::string name = node.attribute_value("name");
483  std::string type = node.attribute_value("type");
484  std::string doc = node.first_node_value_or_default("Description", "");
485  ContainerTypePtr containerInfo = VariantContainerType::FromString(type);
486 
487  // No Container
488  if (!containerInfo->subType)
489  {
490  // generate for non-pointer
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);
494 
495  if (!variantInfo->isBasic(containerInfo->typeId))
496  {
497  // generate for pointer if type is non-basic
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);
501  }
502  }
503  else if (!containerInfo->subType->subType)
504  {
505  //std::string innerDataType = variantInfo->getDataTypeName(containerInfo->subType->typeId);
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";
510 
511  if (containerInfo->typeId == "::armarx::StringValueMapBase")
512  {
513  containerType = "::armarx::StringValueMapPtr";
514  fromStdContainerMethod = fmt("::armarx::StringValueMap::FromStdMap< %s>", innerParamType);
515  paramType = fmt("std::map<std::string, %s>", innerParamType);
516  }
517  else if (containerInfo->typeId == "::armarx::SingleTypeVariantListBase")
518  {
519  containerType = "::armarx::SingleTypeVariantListPtr";
520  fromStdContainerMethod = fmt("::armarx::SingleTypeVariantList::FromStdVector< %s>", innerParamType);
521  paramType = fmt("std::vector< %s>", innerParamType);
522  }
523 
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);
527  }
528  else
529  {
530  //std::string innerDataType = "NOT_FOUND";
531  std::string innerParamType = "NOT_FOUND";
532 
533  if (containerInfo->subType->typeId == "::armarx::StringValueMapBase")
534  {
535  //innerDataType = "::armarx::StringValueMapPtr";
536  innerParamType = "::armarx::StringValueMapPtr";
537  }
538  else if (containerInfo->subType->typeId == "::armarx::SingleTypeVariantListBase")
539  {
540  //innerDataType = "::armarx::SingleTypeVariantListPtr";
541  innerParamType = "::armarx::SingleTypeVariantListPtr";
542  }
543 
544  std::string fromStdContainerMethod = "NOT_FOUND";
545  std::string paramType = "NOT_FOUND";
546  std::string containerType = "NOT_FOUND";
547 
548  if (containerInfo->typeId == "::armarx::StringValueMapBase")
549  {
550  containerType = "::armarx::StringValueMapPtr";
551  fromStdContainerMethod = fmt("::armarx::StringValueMap::FromContainerStdMap< %s>", innerParamType);
552  paramType = fmt("std::map<std::string, %s>", innerParamType);
553  }
554  else if (containerInfo->typeId == "::armarx::SingleTypeVariantListBase")
555  {
556  containerType = "::armarx::SingleTypeVariantListPtr";
557  fromStdContainerMethod = fmt("::armarx::SingleTypeVariantList::FromContainerStdVector< %s>", innerParamType);
558  paramType = fmt("std::vector< %s>", innerParamType);
559  }
560 
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);
564  }
565 
566 }
567 
568 void XmlStateBaseClassGenerator::AddTransitionCodeFunctions(RapidXmlReaderNode stateNode, CppClassPtr targetClass)
569 {
570  auto transitionsNode = stateNode.first_node("Transitions");
571  bool foundUserCodeTransition = false;
572 
573  // TODO obtain this mapping from somewhere else
574  const std::unordered_map<std::string, std::string> packageIncludePaths
575  {
576  {"armar6_rt", "armar6/rt"},
577  {"armar6_skills", "armar6/skills"},
578  // {"armar6_rt", "armar6/rt"},
579  };
580 
581  const auto getPackageIncludePath = [&](const std::string& packageName) -> std::string
582  {
583  if(packageIncludePaths.count(packageName))
584  {
585  return packageIncludePaths.at(packageName);
586  }
587 
588  return packageName;
589  };
590 
591 
592  for (RapidXmlReaderNode& tNode : transitionsNode.nodes("Transition"))
593  {
594  bool userCode = tNode.attribute_as_optional_bool("transitionCodeEnabled", "1", "0", false);
595  if (userCode)
596  {
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");
605 
606  if (!toPackage.empty() && !toGroup.empty() && !toClass.empty())
607  {
608  const std::string packageIncludePath = getPackageIncludePath(toPackage);
609  targetClass->addInclude(fmt("<%s/statecharts/%s/%s.generated.h>", packageIncludePath, toGroup, toClass));
610  }
611  if (!fromPackage.empty() && !fromGroup.empty() && !fromClass.empty())
612  {
613  const std::string packageIncludePath = getPackageIncludePath(fromPackage);
614  targetClass->addInclude(fmt("<%s/statecharts/%s/%s.generated.h>", packageIncludePath, fromGroup, fromClass));
615  }
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;
619  }
620  }
621 
622  if (foundUserCodeTransition)
623  {
624  std::string currentStateName = stateNode.attribute_value("name");
625  CppMethodPtr method = targetClass->addPublicMethod("void defineSubstates()");
626  method->addLine("XMLStateTemplate < StateType >::defineSubstates();");
627  method->addLine("TransitionIceBase t;");
628  for (RapidXmlReaderNode& tNode : transitionsNode.nodes("Transition"))
629  {
630  bool userCode = tNode.attribute_as_optional_bool("transitionCodeEnabled", "1", "0", false);
631  if (userCode)
632  {
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);
646 
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));
649 
650  }
651  }
652  }
653 
654 }
655 
656 std::string XmlStateBaseClassGenerator::fmt(const std::string& fmt, const std::string& arg1)
657 {
658  return str(boost::format(fmt) % arg1);
659 }
660 
661 std::string XmlStateBaseClassGenerator::fmt(const std::string& fmt, const std::string& arg1, const std::string& arg2)
662 {
663  return str(boost::format(fmt) % arg1 % arg2);
664 }
665 
666 std::string XmlStateBaseClassGenerator::fmt(const std::string& fmt, const std::string& arg1, const std::string& arg2, const std::string& arg3)
667 {
668  return str(boost::format(fmt) % arg1 % arg2 % arg3);
669 }
670 
671 std::string XmlStateBaseClassGenerator::generateDocString(RapidXmlReaderNode stateNode, const std::string& packageName, const std::vector<std::string>& namespaces, bool isPublicState)
672 {
673  std::string className = stateNode.attribute_value("name");
674  auto docNode = stateNode.first_node("Description");
675  std::string docString;
676  docString += "@class " + className + "GeneratedBase\n";
677 
678  if (namespaces.size() != 0)
679  {
680  docString += "@ingroup " + packageName + "-" + *namespaces.rbegin() + (isPublicState ? "" : "-Substates") + "\n";
681  }
682 
683  if (docNode.is_valid())
684  {
685  docString += docNode.value();
686  }
687 
688  docString += generateParameterTableString(stateNode);
689 
690  auto graphString = generateDotGraphString(stateNode);
691 
692  if (!graphString.empty())
693  {
694  docString += "\n\n" + graphString;
695  }
696 
697  return docString;
698 }
699 
700 std::string XmlStateBaseClassGenerator::generateParameterTableString(RapidXmlReaderNode stateNode)
701 {
702  std::string result;
703 
704 
705  /**
706  for (RapidXmlReaderNode inputParameter : stateNode.nodes("InputParameters", "Parameter"))
707  {
708  result +=
709  }
710 
711 
712 
713  auto inputParameters = stateNode.first_node("InputParameters");
714  if(inputParameters.first_node("Parameter").is_valid())
715  {
716  result = "\n \n Input parameters: \n";
717  result += "name | type | description \n";
718  for (RapidXmlReaderNode curParameterNode = inputParameters.first_node();
719  curParameterNode.is_valid();
720  curParameterNode = curParameterNode.next_sibling("Parameter"))
721  {
722  result
723  }
724 
725  }
726  */
727 
728 
729  return result;
730 
731 
732 }
733 
734 
735 std::string XmlStateBaseClassGenerator::generateDotGraphString(RapidXmlReaderNode stateNode)
736 {
737  std::string result;
738  auto transitions = stateNode.first_node("Transitions");
739 
740  if (transitions.first_node("Transition").is_valid())
741  {
742 
743  result = "\n \nTransitiongraph of the substates:\n";
744  result += "@dot\n\tdigraph States {\n";
745 
746  for (RapidXmlReaderNode curTransitionNode = transitions.first_node("Transition");
747  curTransitionNode.is_valid();
748  curTransitionNode = curTransitionNode.next_sibling("Transition"))
749  {
750  if (curTransitionNode.has_attribute("from")
751  && curTransitionNode.has_attribute("to")
752  && curTransitionNode.has_attribute("eventName"))
753  {
754  result += "\t\t" + curTransitionNode.attribute_value("from") + "->" +
755  curTransitionNode.attribute_value("to")
756  + "[ label=\"" + curTransitionNode.attribute_value("eventName") + "\" ];\n";
757  }
758  }
759 
760  result += "}\n@enddot";
761  return result;
762  }
763 
764  return "";
765 }
766 
767 DoxDocPtr XmlStateBaseClassGenerator::generateDoxDoc(RapidXmlReaderNode stateNode, const std::string& packageName, std::vector<std::string>& namespaces, bool isPublicState, VariantInfoPtr variantInfo, Ice::CommunicatorPtr communicator)
768 {
769  std::string className = stateNode.attribute_value("name");
770  DoxDocPtr doc(new DoxDoc());
771 
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));
774 
775  if (!isPublicState)
776  {
777  doxGroupName += "-Substates";
778  }
779 
780  doc->addLine(fmt("@ingroup %s\n", doxGroupName));
781 
782  std::string doxBrief;
783  std::string doxDescription = stateNode.first_node_value_or_default("Description", "");
784 
785  if (doxDescription.size() > 0)
786  {
787  std::vector<std::string> descLines = simox::alg::split(doxDescription, ".");
788  doxBrief = descLines[0];
789  doc->addLine(fmt("@brief %s\n", doxBrief));
790  }
791  else
792  {
793  doxBrief = fmt("@brief Brief description of state %s\n", className);
794  doc->addLine(doxBrief);
795  }
796 
797 
798  // input parameters
799  RapidXmlReaderNode inputParameters = stateNode.first_node("InputParameters");
800 
801  if (inputParameters.first_node("Parameter").is_valid())
802  {
803  doc->addLine("Input parameters:");
804  doc->addParameterTable(inputParameters, variantInfo, communicator);
805  }
806 
807  // local parameters
808  RapidXmlReaderNode localParameters = stateNode.first_node("LocalParameters");
809 
810  if (localParameters.first_node("Parameter").is_valid())
811  {
812  doc->addLine("Local parameters:");
813  doc->addParameterTable(localParameters, variantInfo, communicator);
814  }
815 
816  // output parameters
817  RapidXmlReaderNode outputParameters = stateNode.first_node("OutputParameters");
818 
819  if (outputParameters.first_node("Parameter").is_valid())
820  {
821  doc->addLine("Output parameters");
822  doc->addParameterTable(outputParameters, variantInfo, communicator);
823  }
824 
825  RapidXmlReaderNode transitions = stateNode.first_node("Transitions");
826 
827  if (transitions.first_node("Transition").is_valid())
828  {
829  doc->addLine("Transition graph");
830  doc->addTransitionGraph(transitions);
831  }
832 
833 
834  doc->addLine(fmt("@class %sGeneratedBase", className));
835 
836  if (namespaces.size() != 0)
837  {
838  //doc->addLine(fmt("@ingroup %s-%s%s", packageName, namespaces.at(namespaces.size() - 1), isPublicState ? "" : "-Substates"));
839  //doc->addLine(fmt("@ingroup %s", doxGroupName));
840  doc->addLine(fmt("@ingroup %s-%s-State", packageName, className));
841  }
842 
843  doc->addLine(fmt("For a documentation of this state see @ref %s-%s-State", packageName, className));
844 
845  if (doxBrief.size() > 0)
846  {
847  doc->addLine(doxBrief);
848  }
849 
850  doc->addLine(doxDescription.substr(0, 80));
851 
852 
853  return doc;
854 }
armarx::RapidXmlReaderPtr
std::shared_ptr< RapidXmlReader > RapidXmlReaderPtr
Definition: RapidXmlReader.h:66
str
std::string str(const T &t)
Definition: UserAssistedSegmenterGuiWidgetController.cpp:42
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:36
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:256
armarx::RapidXmlReaderNode::attribute_value
std::string attribute_value(const char *attrName) const
Definition: RapidXmlReader.h:198
armarx::DoxDocPtr
std::shared_ptr< DoxDoc > DoxDocPtr
Definition: DoxDoc.h:38
armarx::XmlStateBaseClassGenerator::GetUsedInnerNonBasicVariantTypes
static std::set< std::string > GetUsedInnerNonBasicVariantTypes(RapidXmlReaderNode stateNode, VariantInfoPtr variantInfo)
Definition: XmlStateBaseClassGenerator.cpp:55
armarx::CppFieldPtr
std::shared_ptr< CppField > CppFieldPtr
Definition: CppField.h:34
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:44
armarx::VariantInfo::ProxyEntryPtr
std::shared_ptr< ProxyEntry > ProxyEntryPtr
Definition: VariantInfo.h:71
armarx::XmlStateBaseClassGenerator::XmlStateBaseClassGenerator
XmlStateBaseClassGenerator()
Definition: XmlStateBaseClassGenerator.cpp:39
armarx::CppClass
Definition: CppClass.h:38
armarx::CppMethodPtr
std::shared_ptr< CppMethod > CppMethodPtr
Definition: CppMethod.h:32
armarx::RapidXmlReaderNode
Definition: RapidXmlReader.h:68
ARMARX_WARNING_S
#define ARMARX_WARNING_S
Definition: Logging.h:206
armarx::CppClass::WriteCpp
static void WriteCpp(const std::vector< CppClassPtr > &classes, const CppWriterPtr &writer)
Definition: CppClass.cpp:49
armarx::RapidXmlReaderNode::value
std::string value() const
Definition: RapidXmlReader.h:313
CMakePackageFinder.h
armarx::CppWriter
Definition: CppWriter.h:37
armarx::XmlStateBaseClassGenerator::GetIncludesForInnerNonBasicVariantTypes
static std::set< std::string > GetIncludesForInnerNonBasicVariantTypes(RapidXmlReaderNode stateNode, VariantInfoPtr variantInfo)
Definition: XmlStateBaseClassGenerator.cpp:78
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:374
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:158
armarx::RapidXmlReaderNode::is_valid
bool is_valid() const
Definition: RapidXmlReader.h:392
armarx::CppField
Definition: CppField.h:36
armarx::CppWriterPtr
std::shared_ptr< CppWriter > CppWriterPtr
Definition: CppWriter.h:35
armarx::CppMethod
Definition: CppMethod.h:34
Logging.h
ArmarXDataPath.h
armarx::RapidXmlReaderNode::first_node
RapidXmlReaderNode first_node(const char *name=nullptr) const
Definition: RapidXmlReader.h:140
armarx::DoxDoc
Definition: DoxDoc.h:40
armarx::VariantInfo::LibEntryPtr
std::shared_ptr< LibEntry > LibEntryPtr
Definition: VariantInfo.h:172
armarx::VariantContainerType::FromString
static ContainerTypePtr FromString(const std::string &typeStr)
Definition: VariantContainer.cpp:262
armarx
This file offers overloads of toIce() and fromIce() functions for STL container types.
Definition: ArmarXTimeserver.cpp:28
armarx::split
std::vector< std::string > split(const std::string &source, const std::string &splitBy, bool trimElements=false, bool removeEmptyElements=false)
Definition: StringHelpers.cpp:36
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