From ad853e17807cbd527e9eddbfbba05014c9700d30 Mon Sep 17 00:00:00 2001 From: RlanderRISCSW Date: Wed, 17 Jan 2024 11:29:52 +0100 Subject: [PATCH] fixed ValidateChoices function for optional choices --- src/lib/CodeGen.cpp | 44 +++++++++++++++++++++++++++++--- src/lib/SchemaParser.cpp | 14 ++++++++++ src/lib/SchemaParser.h | 1 + src/lib/TypeSystem.cpp | 1 + src/lib/TypeSystem.h | 1 + test/data/optionalchoice/ref.cpp | 44 +++++++++++++++++--------------- 6 files changed, 80 insertions(+), 25 deletions(-) diff --git a/src/lib/CodeGen.cpp b/src/lib/CodeGen.cpp index 055e07a..fcafe43 100644 --- a/src/lib/CodeGen.cpp +++ b/src/lib/CodeGen.cpp @@ -1063,16 +1063,52 @@ namespace tigl { cpp << "true // " << f.fieldName() << " is optional in choice"; } - void operator()(const Choice& c) { + void operator()(const Choice& ch) { cpp << "("; { Scope s(cpp); - for (const auto& cc : c.options) { - (*this)(cc, c); - if (&cc != &c.options.back()) + boost::optional additionalScope; + + if (ch.minOccurs == 0) { + cpp << "// all uninitialized is valid since choice is optional!"; + cpp << "!("; + { + Scope s(cpp); + + RecursiveColletor parentCollector; + parentCollector(ch); + auto& allIndices = parentCollector.indices; + + auto unique = [](std::vector& v) { + std::sort(std::begin(v), std::end(v)); + const auto it = std::unique(std::begin(v), std::end(v)); + v.erase(it, std::end(v)); + }; + unique(allIndices); + + for (const auto& i : allIndices) { + writeIsFieldThere(cpp, c.fields[i]); + if (&i != &allIndices.back()) + cpp << "||"; + } + } + cpp << ")"; + cpp << "||"; + cpp << "("; + additionalScope.emplace(cpp); + } + + for (const auto &ces : ch.options) { + (*this)(ces, ch); + if (&ces != &ch.options.back()) cpp << "+"; } cpp << "== 1"; + + if (additionalScope) { + additionalScope.reset(); + cpp << ")"; + } } cpp << ")"; } diff --git a/src/lib/SchemaParser.cpp b/src/lib/SchemaParser.cpp index 25ea9bc..31737ca 100644 --- a/src/lib/SchemaParser.cpp +++ b/src/lib/SchemaParser.cpp @@ -64,6 +64,20 @@ namespace tigl { // Choice ch; ch.xpath = xpath; + + // minOccurs + if (!document.checkAttribute(xpath, "minOccurs")) + ch.minOccurs = 1; + else { + const auto minOccurs = document.textAttribute(xpath, "minOccurs"); + const auto minOccursInt = std::stoi(minOccurs); + if (minOccursInt < 0) + throw std::runtime_error("minOccurs is negative: " + xpath); + else if (minOccursInt > 1) + throw std::runtime_error("support for minOccurs>1 not implemented for choices yet: " + xpath); + ch.minOccurs = minOccursInt; + } + document.forEachChild(xpath, "xsd:element", [&](const std::string& xpath) { ch.elements.push_back(readElement(xpath, containingTypeName)); }); diff --git a/src/lib/SchemaParser.h b/src/lib/SchemaParser.h index 4b6b20c..5512705 100644 --- a/src/lib/SchemaParser.h +++ b/src/lib/SchemaParser.h @@ -54,6 +54,7 @@ namespace tigl { struct Choice : XSDElement { std::vector> elements; + unsigned int minOccurs; }; struct SimpleContent : XSDElement { diff --git a/src/lib/TypeSystem.cpp b/src/lib/TypeSystem.cpp index 6f90810..fb9c160 100644 --- a/src/lib/TypeSystem.cpp +++ b/src/lib/TypeSystem.cpp @@ -117,6 +117,7 @@ namespace tigl { const auto countBefore = members.size(); Choice choice; + choice.minOccurs = c.minOccurs; for (const auto& v : c.elements | boost::adaptors::indexed(1)) { // collect members of one choice auto indices = choiceIndices; diff --git a/src/lib/TypeSystem.h b/src/lib/TypeSystem.h index cfd228c..d578fa2 100644 --- a/src/lib/TypeSystem.h +++ b/src/lib/TypeSystem.h @@ -103,6 +103,7 @@ namespace tigl { using ChoiceElements = std::vector>>; struct Choice { + unsigned int minOccurs; std::vector options; }; diff --git a/test/data/optionalchoice/ref.cpp b/test/data/optionalchoice/ref.cpp index 69463a1..aefd1b3 100644 --- a/test/data/optionalchoice/ref.cpp +++ b/test/data/optionalchoice/ref.cpp @@ -158,34 +158,36 @@ namespace generated { return ( - // all uninitialized is valid since choice is optional - !( - m_a_choice1.is_initialized() - || - m_b_choice2.is_initialized() - ) - || ( - ( - // mandatory elements of this choice must be there + // all uninitialized is valid since choice is optional! + !( m_a_choice1.is_initialized() - && - // elements of other choices must not be there - !( - m_b_choice2.is_initialized() - ) + || + m_b_choice2.is_initialized() ) - + + || ( - // mandatory elements of this choice must be there - m_b_choice2.is_initialized() - && - // elements of other choices must not be there - !( + ( + // mandatory elements of this choice must be there m_a_choice1.is_initialized() + && + // elements of other choices must not be there + !( + m_b_choice2.is_initialized() + ) + ) + + + ( + // mandatory elements of this choice must be there + m_b_choice2.is_initialized() + && + // elements of other choices must not be there + !( + m_a_choice1.is_initialized() + ) ) + == 1 ) - == 1 ) ) ;