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
38using namespace armarx;
39
43
44std::string
45XmlStateBaseClassGenerator::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
65std::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
90std::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
120std::vector<CppClassPtr>
121XmlStateBaseClassGenerator::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
401std::set<std::string>
402XmlStateBaseClassGenerator::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
427void
428XmlStateBaseClassGenerator::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
527void
528XmlStateBaseClassGenerator::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
541void
542XmlStateBaseClassGenerator::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
646void
647XmlStateBaseClassGenerator::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
759std::string
760XmlStateBaseClassGenerator::fmt(const std::string& fmt, const std::string& arg1)
761{
762 return str(boost::format(fmt) % arg1);
763}
764
765std::string
766XmlStateBaseClassGenerator::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
773std::string
774XmlStateBaseClassGenerator::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
782std::string
783XmlStateBaseClassGenerator::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
816std::string
817XmlStateBaseClassGenerator::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
849std::string
850XmlStateBaseClassGenerator::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
882XmlStateBaseClassGenerator::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}
std::string str(const T &t)
static void WriteCpp(const std::vector< CppClassPtr > &classes, const CppWriterPtr &writer)
Definition CppClass.cpp:54
RapidXmlReaderNode first_node(const char *name=nullptr) const
std::vector< RapidXmlReaderNode > nodes(const char *name=nullptr) const
std::string first_node_value_or_default(const char *name, const std::string &defaultValue) const
std::string attribute_value(const char *attrName) const
static ContainerTypePtr FromString(const std::string &typeStr)
std::shared_ptr< LibEntry > LibEntryPtr
std::shared_ptr< ProxyEntry > ProxyEntryPtr
Definition VariantInfo.h:76
static std::string GenerateCpp(std::vector< std::string > namespaces, RapidXmlReaderPtr reader, const std::vector< std::string > &proxies, bool contextGenerationEnabled, std::string groupName, VariantInfoPtr variantInfo)
static std::set< std::string > GetIncludesForInnerNonBasicVariantTypes(RapidXmlReaderNode stateNode, VariantInfoPtr variantInfo)
static std::set< std::string > GetUsedInnerNonBasicVariantTypes(RapidXmlReaderNode stateNode, VariantInfoPtr variantInfo)
#define ARMARX_WARNING_S
The logging level for unexpected behaviour, but not a serious problem.
Definition Logging.h:213
::IceInternal::Handle<::Ice::Communicator > CommunicatorPtr
Definition IceManager.h:49
This file offers overloads of toIce() and fromIce() functions for STL container types.
std::shared_ptr< CppClass > CppClassPtr
Definition CppClass.h:35
std::shared_ptr< DoxDoc > DoxDocPtr
Definition DoxDoc.h:40
std::shared_ptr< RapidXmlReader > RapidXmlReaderPtr
std::shared_ptr< CppWriter > CppWriterPtr
Definition CppWriter.h:35
std::shared_ptr< VariantInfo > VariantInfoPtr
Definition VariantInfo.h:39
std::shared_ptr< CppCtor > CppCtorPtr
Definition CppCtor.h:31
std::shared_ptr< CppMethod > CppMethodPtr
Definition CppMethod.h:31
std::shared_ptr< CppField > CppFieldPtr
Definition CppField.h:33
constexpr auto n() noexcept