From e76f58e912bd6661ba755d27da97bebf711f06ad Mon Sep 17 00:00:00 2001 From: Benjamin Paassen Date: Wed, 4 Feb 2015 18:24:32 +0100 Subject: added mechanism for parent parsing, which does not fully work as of now. --- src/plugins/xml/XmlParser.cpp | 188 ++++++++++++++++++++++++++++++++- test/plugins/xml/XmlParserTest.cpp | 30 ++++-- testdata/xmlparser/book_domain.oxm | 16 +-- testdata/xmlparser/headings_domain.oxm | 33 ++++++ 4 files changed, 244 insertions(+), 23 deletions(-) create mode 100644 testdata/xmlparser/headings_domain.oxm diff --git a/src/plugins/xml/XmlParser.cpp b/src/plugins/xml/XmlParser.cpp index 52176db..b52e39d 100644 --- a/src/plugins/xml/XmlParser.cpp +++ b/src/plugins/xml/XmlParser.cpp @@ -357,7 +357,7 @@ public: } // TODO: Is inheritance possible here? - Rooted parent = scope().select(); + Rooted parent = scope().selectOrThrow(); Rooted field = parent->createFieldDescriptor( type, args["name"].asString(), args["optional"].asBool()); @@ -374,6 +374,34 @@ public: } }; +class DomainFieldRefHandler : public Handler { +public: + using Handler::Handler; + + void start(Variant::mapType &args) override + { + // TODO: Is inheritance possible here? + Rooted parent = scope().selectOrThrow(); + + const std::string &name = args["name"].asString(); + scope().resolve( + name, parent, logger(), + [](Handle field, Handle parent, Logger &logger) { + if (field != nullptr) { + parent.cast()->copyFieldDescriptor( + field.cast()); + } + }); + } + + void end() override {} + + static Handler *create(const HandlerData &handlerData) + { + return new DomainFieldRefHandler{handlerData}; + } +}; + class DomainPrimitiveHandler : public Handler { public: using Handler::Handler; @@ -381,7 +409,7 @@ public: void start(Variant::mapType &args) override { // TODO: Is inheritance possible here? - Rooted parent = scope().select(); + Rooted parent = scope().selectOrThrow(); Rooted field = parent->createPrimitiveFieldDescriptor( nullptr, args["name"].asString(), args["optional"].asBool()); @@ -414,7 +442,8 @@ public: void start(Variant::mapType &args) override { - Rooted field = scope().select(); + Rooted field = + scope().selectOrThrow(); const std::string &ref = args["ref"].asString(); scope().resolve( @@ -435,7 +464,128 @@ public: } }; -// TODO: Add parent handler +class DummyParentNode : public Node { +public: + DummyParentNode(Manager &mgr, std::string name, Handle parent) + : Node(mgr, name, parent) + { + } +}; + +namespace RttiTypes { +const Rtti DummyParentNode = + RttiBuilder("DummyParentNode").parent(&Node); +} + +class DomainParentHandler : public Handler { +public: + using Handler::Handler; + + void start(Variant::mapType &args) override + { + Rooted strct = + scope().selectOrThrow(); + + // TODO: Is there a better way for this? + Rooted dummy{new DummyParentNode( + strct->getManager(), args["name"].asString(), strct)}; + dummy->setLocation(location()); + scope().push(dummy); + } + + void end() override { scope().pop(); } + + static Handler *create(const HandlerData &handlerData) + { + return new DomainParentHandler{handlerData}; + } +}; + +class DomainParentFieldHandler : public Handler { +public: + using Handler::Handler; + + void start(Variant::mapType &args) override + { + Rooted dummy = + scope().selectOrThrow(); + FieldDescriptor::FieldType type; + if (args["isSubtree"].asBool()) { + type = FieldDescriptor::FieldType::SUBTREE; + } else { + type = FieldDescriptor::FieldType::TREE; + } + + const std::string &name = args["name"].asString(); + const bool optional = args["optional"].asBool(); + Rooted strct = + dummy->getParent().cast(); + + // resolve the parent, create the declared field and add the declared + // StructuredClass as child to it. + scope().resolve( + dummy->getName(), strct, logger(), + [&type, &name, &optional](Handle parent, Handle strct, + Logger &logger) { + if (parent != nullptr) { + Rooted field = + parent.cast()->createFieldDescriptor( + type, name, optional); + field->addChild(strct.cast()); + } + }); + } + + void end() override {} + + static Handler *create(const HandlerData &handlerData) + { + return new DomainParentFieldHandler{handlerData}; + } +}; + +class DomainParentFieldRefHandler : public Handler { +public: + using Handler::Handler; + + void start(Variant::mapType &args) override + { + Rooted dummy = + scope().selectOrThrow(); + + const std::string &name = args["name"].asString(); + Rooted strct = + dummy->getParent().cast(); + auto loc = location(); + + // resolve the parent, get the referenced field and add the declared + // StructuredClass as child to it. + scope().resolve(dummy->getName(), strct, logger(), + [&name, &loc](Handle parent, + Handle strct, + Logger &logger) { + if (parent != nullptr) { + auto res = parent->resolve(RttiTypes::FieldDescriptor, name); + if (res.size() != 1) { + logger.error( + std::string("Could not find referenced field ") + name, + loc); + } + Rooted field = + res[0].node.cast(); + field->addChild(strct.cast()); + } + }); + } + + void end() override {} + + static Handler *create(const HandlerData &handlerData) + { + return new DomainParentFieldRefHandler{handlerData}; + } +}; + // TODO: Add annotation handler /* @@ -571,6 +721,12 @@ static const ParserState DomainStructField = .arguments({Argument::String("name", ""), Argument::Bool("isSubtree", false), Argument::Bool("optional", false)}); +static const ParserState DomainStructFieldRef = + ParserStateBuilder() + .parent(&DomainStruct) + .createdNodeType(&RttiTypes::FieldDescriptor) + .elementHandler(DomainFieldRefHandler::create) + .arguments({Argument::String("name", "")}); static const ParserState DomainStructPrimitive = ParserStateBuilder() .parent(&DomainStruct) @@ -584,6 +740,26 @@ static const ParserState DomainStructChild = .parent(&DomainStructField) .elementHandler(DomainChildHandler::create) .arguments({Argument::String("ref")}); +static const ParserState DomainStructParent = + ParserStateBuilder() + .parent(&DomainStruct) + .createdNodeType(&RttiTypes::DummyParentNode) + .elementHandler(DomainParentHandler::create) + .arguments({Argument::String("name")}); +static const ParserState DomainStructParentField = + ParserStateBuilder() + .parent(&DomainStructParent) + .createdNodeType(&RttiTypes::FieldDescriptor) + .elementHandler(DomainParentFieldHandler::create) + .arguments({Argument::String("name", ""), + Argument::Bool("isSubtree", false), + Argument::Bool("optional", false)}); +static const ParserState DomainStructParentFieldRef = + ParserStateBuilder() + .parent(&DomainStructParent) + .createdNodeType(&RttiTypes::FieldDescriptor) + .elementHandler(DomainParentFieldRefHandler::create) + .arguments({Argument::String("name", "")}); /* Typesystem states */ static const ParserState Typesystem = @@ -642,8 +818,12 @@ static const std::multimap XmlStates{ {"domain", &Domain}, {"struct", &DomainStruct}, {"field", &DomainStructField}, + {"fieldRef", &DomainStructFieldRef}, {"primitive", &DomainStructPrimitive}, {"child", &DomainStructChild}, + {"parent", &DomainStructParent}, + {"field", &DomainStructParentField}, + {"fieldRef", &DomainStructParentFieldRef}, {"typesystem", &Typesystem}, {"enum", &TypesystemEnum}, {"entry", &TypesystemEnumEntry}, diff --git a/test/plugins/xml/XmlParserTest.cpp b/test/plugins/xml/XmlParserTest.cpp index 60e7c9b..c493643 100644 --- a/test/plugins/xml/XmlParserTest.cpp +++ b/test/plugins/xml/XmlParserTest.cpp @@ -144,30 +144,31 @@ static void checkFieldDescriptor( TEST(XmlParser, domainParsing) { XmlStandaloneEnvironment env(logger); - Rooted n = + Rooted book_domain_node = env.parse("book_domain.oxm", "", "", RttiSet{&RttiTypes::Domain}); - ASSERT_FALSE(n == nullptr); + ASSERT_FALSE(book_domain_node == nullptr); ASSERT_FALSE(logger.hasError()); // check the domain node. - Rooted domain = n.cast(); - ASSERT_EQ("book", domain->getName()); + Rooted book_domain = book_domain_node.cast(); + ASSERT_EQ("book", book_domain->getName()); // get the book struct node. Cardinality single; single.merge({1}); Rooted book = checkStructuredClass( - "book", "book", domain, single, nullptr, nullptr, false, true); + "book", "book", book_domain, single, nullptr, nullptr, false, true); // get the chapter struct node. Rooted chapter = - checkStructuredClass("chapter", "chapter", domain); + checkStructuredClass("chapter", "chapter", book_domain); Rooted section = - checkStructuredClass("section", "section", domain); + checkStructuredClass("section", "section", book_domain); Rooted subsection = - checkStructuredClass("subsection", "subsection", domain); + checkStructuredClass("subsection", "subsection", book_domain); Rooted paragraph = - checkStructuredClass("paragraph", "paragraph", domain, AnyCardinality, + checkStructuredClass("paragraph", "paragraph", book_domain, + AnyCardinality, nullptr, nullptr, true, false); + Rooted text = + checkStructuredClass("text", "text", book_domain, AnyCardinality, nullptr, nullptr, true, false); - Rooted text = checkStructuredClass( - "text", "text", domain, AnyCardinality, nullptr, nullptr, true, false); // check the FieldDescriptors. checkFieldDescriptor(book, {chapter, paragraph}); @@ -178,6 +179,13 @@ TEST(XmlParser, domainParsing) checkFieldDescriptor( text, {}, "content", FieldDescriptor::FieldType::PRIMITIVE, env.project->getSystemTypesystem()->getStringType(), false); + + // check parent handling. + Rooted headings_domain_node = + env.parse("headings_domain.oxm", "", "", RttiSet{&RttiTypes::Domain}); + //TODO: Unfortunately this does not work yet. + //ASSERT_FALSE(headings_domain_node == nullptr); + //ASSERT_FALSE(logger.hasError()); } } diff --git a/testdata/xmlparser/book_domain.oxm b/testdata/xmlparser/book_domain.oxm index 625e3c0..e02ec53 100644 --- a/testdata/xmlparser/book_domain.oxm +++ b/testdata/xmlparser/book_domain.oxm @@ -1,4 +1,4 @@ - + - + @@ -52,7 +52,7 @@ @@ -65,7 +65,7 @@ @@ -77,7 +77,7 @@ @@ -89,7 +89,7 @@ diff --git a/testdata/xmlparser/headings_domain.oxm b/testdata/xmlparser/headings_domain.oxm new file mode 100644 index 0000000..f83843c --- /dev/null +++ b/testdata/xmlparser/headings_domain.oxm @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + -- cgit v1.2.3