From 9a5ca5397cc7903728e808c861f0a7fe1198bb43 Mon Sep 17 00:00:00 2001 From: Benjamin Paassen Date: Wed, 4 Feb 2015 00:20:57 +0100 Subject: further work on domain parsing. This is not a working state yet. --- src/plugins/xml/XmlParser.cpp | 128 ++++++++++++++++++++++++++++++++++--- test/plugins/xml/XmlParserTest.cpp | 29 +++++++-- testdata/xmlparser/book_domain.oxm | 98 ++++++++++++++++++++++++++++ 3 files changed, 242 insertions(+), 13 deletions(-) create mode 100644 testdata/xmlparser/book_domain.oxm diff --git a/src/plugins/xml/XmlParser.cpp b/src/plugins/xml/XmlParser.cpp index f4e5caf..010b707 100644 --- a/src/plugins/xml/XmlParser.cpp +++ b/src/plugins/xml/XmlParser.cpp @@ -235,6 +235,10 @@ public: } }; +/* + * Domain Handlers + */ + class DomainHandler : public Handler { public: using Handler::Handler; @@ -264,8 +268,6 @@ public: { scope().setFlag(ParserFlag::POST_HEAD, true); - const std::string &isa = args["isa"].asString(); - Rooted domain = scope().select(); Rooted structuredClass = domain->createStructuredClass( args["name"].asString(), args["cardinality"].asCardinality(), @@ -273,6 +275,7 @@ public: args["isRoot"].asBool()); structuredClass->setLocation(location()); + const std::string &isa = args["isa"].asString(); if (!isa.empty()) { scope().resolve( isa, structuredClass, logger(), @@ -296,6 +299,105 @@ public: } }; +class DomainFieldHandler : public Handler { +public: + using Handler::Handler; + + void start(Variant::mapType &args) override + { + FieldDescriptor::FieldType type; + if (args["isSubtree"].asBool()) { + type = FieldDescriptor::FieldType::SUBTREE; + } else { + type = FieldDescriptor::FieldType::TREE; + } + + // TODO: Is inheritance possible here? + Rooted parent = scope().select(); + + Rooted field = parent->createFieldDescriptor( + type, args["name"].asString(), args["optional"].asBool()); + field->setLocation(location()); + + scope().push(field); + } + + void end() override { scope().pop(); } + + static Handler *create(const HandlerData &handlerData) + { + return new DomainFieldHandler{handlerData}; + } +}; + +class DomainPrimitiveHandler : public Handler { +public: + using Handler::Handler; + + void start(Variant::mapType &args) override + { + // TODO: Is inheritance possible here? + Rooted parent = scope().select(); + + Rooted field = parent->createPrimitiveFieldDescriptor( + nullptr, args["name"].asString(), args["optional"].asBool()); + field->setLocation(location()); + + const std::string &type = args["type"].asString(); + scope().resolve( + type, field, logger(), + [](Handle type, Handle field, Logger &logger) { + if (type != nullptr) { + field.cast()->setPrimitiveType( + type.cast()); + } + }); + + scope().push(field); + } + + void end() override { scope().pop(); } + + static Handler *create(const HandlerData &handlerData) + { + return new DomainPrimitiveHandler{handlerData}; + } +}; + +class DomainChildHandler : public Handler { +public: + using Handler::Handler; + + void start(Variant::mapType &args) override + { + Rooted field = scope().select(); + + const std::string &ref = args["ref"].asString(); + scope().resolve( + ref, field, logger(), + [](Handle child, Handle field, Logger &logger) { + if (child != nullptr) { + field.cast()->addChild( + child.cast()); + } + }); + } + + void end() override {} + + static Handler *create(const HandlerData &handlerData) + { + return new DomainChildHandler{handlerData}; + } +}; + +//TODO: Add parent handler +//TODO: Add annotation handler + +/* + * Import and Include Handler + */ + class ImportIncludeHandler : public Handler { public: using Handler::Handler; @@ -417,19 +519,27 @@ static const ParserState DomainStruct = Argument::Bool("isRoot", false), Argument::Bool("transparent", false), Argument::String("isa", "")}); -static const ParserState DomainStructFields = - ParserStateBuilder().parent(&DomainStruct).arguments({}); static const ParserState DomainStructField = ParserStateBuilder() - .parent(&DomainStructFields) + .parent(&DomainStruct) .createdNodeType(&RttiTypes::FieldDescriptor) + .elementHandler(DomainFieldHandler::create) .arguments({Argument::String("name", ""), Argument::Bool("isSubtree", false), Argument::Bool("optional", false)}); static const ParserState DomainStructPrimitive = - ParserStateBuilder().parent(&DomainStructFields).arguments( - {Argument::String("name", ""), Argument::Bool("optional", false), - Argument::String("type")}); + ParserStateBuilder() + .parent(&DomainStruct) + .createdNodeType(&RttiTypes::FieldDescriptor) + .elementHandler(DomainPrimitiveHandler::create) + .arguments({Argument::String("name", ""), + Argument::Bool("optional", false), + Argument::String("type")}); +static const ParserState DomainStructChild = + ParserStateBuilder() + .parent(&DomainStructField) + .elementHandler(DomainChildHandler::create) + .arguments({Argument::String("ref")}); /* Typesystem states */ static const ParserState Typesystem = @@ -481,9 +591,9 @@ static const std::multimap XmlStates{ {"document", &Document}, {"domain", &Domain}, {"struct", &DomainStruct}, - {"fields", &DomainStructFields}, {"field", &DomainStructField}, {"primitive", &DomainStructPrimitive}, + {"child", &DomainStructChild}, {"typesystem", &Typesystem}, {"enum", &TypesystemEnum}, {"struct", &TypesystemStruct}, diff --git a/test/plugins/xml/XmlParserTest.cpp b/test/plugins/xml/XmlParserTest.cpp index 0f37d0a..b90f39e 100644 --- a/test/plugins/xml/XmlParserTest.cpp +++ b/test/plugins/xml/XmlParserTest.cpp @@ -22,6 +22,7 @@ #include #include +#include #include #include #include @@ -48,10 +49,8 @@ struct XmlStandaloneEnvironment : public StandaloneEnvironment { fileLocator.addUnittestSearchPath("xmlparser"); registry.registerDefaultExtensions(); - registry.registerParser( - {"text/vnd.ousia.oxm", "text/vnd.ousia.oxd"}, - {&RttiTypes::Node}, - &xmlParser); + registry.registerParser({"text/vnd.ousia.oxm", "text/vnd.ousia.oxd"}, + {&RttiTypes::Node}, &xmlParser); registry.registerResourceLocator(&fileLocator); } }; @@ -73,5 +72,27 @@ TEST(XmlParser, generic) env.manager.exportGraphviz("xmlDocument.dot"); #endif } + +TEST(XmlParser, domainParsing) +{ + XmlStandaloneEnvironment env(logger); + Rooted n = + env.parse("book_domain.oxm", "", "", RttiSet{&RttiTypes::Domain}); + ASSERT_FALSE(n.isNull()); + // check the domain node. + Rooted domain = n.cast(); + ASSERT_EQ("book", domain->getName()); + // get the book struct node. + auto res = domain->resolve(RttiTypes::StructuredClass, "book"); + ASSERT_EQ(1, res.size()); + Rooted bookStruct = res[0].node.cast(); + ASSERT_EQ("book", bookStruct->getName()); + Cardinality single; + single.merge({1}); + ASSERT_EQ(single, bookStruct->getCardinality()); + //TODO: Something is wrong here +// ASSERT_TRUE(bookStruct->isRoot()); + ASSERT_FALSE(bookStruct->isTransparent()); +} } diff --git a/testdata/xmlparser/book_domain.oxm b/testdata/xmlparser/book_domain.oxm new file mode 100644 index 0000000..625e3c0 --- /dev/null +++ b/testdata/xmlparser/book_domain.oxm @@ -0,0 +1,98 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -- cgit v1.2.3