diff options
author | Benjamin Paassen <bpaassen@techfak.uni-bielefeld.de> | 2015-02-04 18:24:32 +0100 |
---|---|---|
committer | Benjamin Paassen <bpaassen@techfak.uni-bielefeld.de> | 2015-02-04 18:24:32 +0100 |
commit | e76f58e912bd6661ba755d27da97bebf711f06ad (patch) | |
tree | 84db508d8d65ad48522ea835f84b21f9f4d4dff9 | |
parent | 0149f97eca604662493e8aa2ebcceecba5fc5b94 (diff) |
added mechanism for parent parsing, which does not fully work as of now.
-rw-r--r-- | src/plugins/xml/XmlParser.cpp | 188 | ||||
-rw-r--r-- | test/plugins/xml/XmlParserTest.cpp | 30 | ||||
-rw-r--r-- | testdata/xmlparser/book_domain.oxm | 16 | ||||
-rw-r--r-- | testdata/xmlparser/headings_domain.oxm | 33 |
4 files changed, 244 insertions, 23 deletions
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<Descriptor> parent = scope().select<Descriptor>(); + Rooted<Descriptor> parent = scope().selectOrThrow<Descriptor>(); Rooted<FieldDescriptor> 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<Descriptor> parent = scope().selectOrThrow<Descriptor>(); + + const std::string &name = args["name"].asString(); + scope().resolve<FieldDescriptor>( + name, parent, logger(), + [](Handle<Node> field, Handle<Node> parent, Logger &logger) { + if (field != nullptr) { + parent.cast<StructuredClass>()->copyFieldDescriptor( + field.cast<FieldDescriptor>()); + } + }); + } + + 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<Descriptor> parent = scope().select<Descriptor>(); + Rooted<Descriptor> parent = scope().selectOrThrow<Descriptor>(); Rooted<FieldDescriptor> field = parent->createPrimitiveFieldDescriptor( nullptr, args["name"].asString(), args["optional"].asBool()); @@ -414,7 +442,8 @@ public: void start(Variant::mapType &args) override { - Rooted<FieldDescriptor> field = scope().select<FieldDescriptor>(); + Rooted<FieldDescriptor> field = + scope().selectOrThrow<FieldDescriptor>(); const std::string &ref = args["ref"].asString(); scope().resolve<StructuredClass>( @@ -435,7 +464,128 @@ public: } }; -// TODO: Add parent handler +class DummyParentNode : public Node { +public: + DummyParentNode(Manager &mgr, std::string name, Handle<Node> parent) + : Node(mgr, name, parent) + { + } +}; + +namespace RttiTypes { +const Rtti DummyParentNode = + RttiBuilder<ousia::DummyParentNode>("DummyParentNode").parent(&Node); +} + +class DomainParentHandler : public Handler { +public: + using Handler::Handler; + + void start(Variant::mapType &args) override + { + Rooted<StructuredClass> strct = + scope().selectOrThrow<StructuredClass>(); + + // TODO: Is there a better way for this? + Rooted<DummyParentNode> 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<DummyParentNode> dummy = + scope().selectOrThrow<DummyParentNode>(); + 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<StructuredClass> strct = + dummy->getParent().cast<StructuredClass>(); + + // resolve the parent, create the declared field and add the declared + // StructuredClass as child to it. + scope().resolve<Descriptor>( + dummy->getName(), strct, logger(), + [&type, &name, &optional](Handle<Node> parent, Handle<Node> strct, + Logger &logger) { + if (parent != nullptr) { + Rooted<FieldDescriptor> field = + parent.cast<Descriptor>()->createFieldDescriptor( + type, name, optional); + field->addChild(strct.cast<StructuredClass>()); + } + }); + } + + 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<DummyParentNode> dummy = + scope().selectOrThrow<DummyParentNode>(); + + const std::string &name = args["name"].asString(); + Rooted<StructuredClass> strct = + dummy->getParent().cast<StructuredClass>(); + auto loc = location(); + + // resolve the parent, get the referenced field and add the declared + // StructuredClass as child to it. + scope().resolve<Descriptor>(dummy->getName(), strct, logger(), + [&name, &loc](Handle<Node> parent, + Handle<Node> 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<FieldDescriptor> field = + res[0].node.cast<FieldDescriptor>(); + field->addChild(strct.cast<StructuredClass>()); + } + }); + } + + 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<std::string, const ParserState *> 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<Node> n = + Rooted<Node> 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> domain = n.cast<Domain>(); - ASSERT_EQ("book", domain->getName()); + Rooted<Domain> book_domain = book_domain_node.cast<Domain>(); + ASSERT_EQ("book", book_domain->getName()); // get the book struct node. Cardinality single; single.merge({1}); Rooted<StructuredClass> 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<StructuredClass> chapter = - checkStructuredClass("chapter", "chapter", domain); + checkStructuredClass("chapter", "chapter", book_domain); Rooted<StructuredClass> section = - checkStructuredClass("section", "section", domain); + checkStructuredClass("section", "section", book_domain); Rooted<StructuredClass> subsection = - checkStructuredClass("subsection", "subsection", domain); + checkStructuredClass("subsection", "subsection", book_domain); Rooted<StructuredClass> paragraph = - checkStructuredClass("paragraph", "paragraph", domain, AnyCardinality, + checkStructuredClass("paragraph", "paragraph", book_domain, + AnyCardinality, nullptr, nullptr, true, false); + Rooted<StructuredClass> text = + checkStructuredClass("text", "text", book_domain, AnyCardinality, nullptr, nullptr, true, false); - Rooted<StructuredClass> 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<Node> 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 @@ -<?xml version="1.0"?> +<?xml version="1.0" standalone="yes"?> <!-- The domain node is the root node of a single domain definition --> <domain name="book"> <!-- We start by declaring the structured classes. This implicitly defines @@ -9,9 +9,9 @@ nor parent, nor transparency, meaning that we refer to the default values. Also note that we need to specify explicitly, which classes are allowed as root nodes. --> - <struct name="book" cardinality="1" isRoot="true"> + <struct name="book" cardinality="{1}" isRoot="true"> <!-- implicitly: - <struct name="book" cardinality="1" isRoot="true" + <struct name="book" cardinality="{1}" isRoot="true" transparent="false" isa="" attributesDescriptor=""> --> <!-- Note that we assume that, if not specified, a @@ -39,7 +39,7 @@ </struct> <struct name="chapter"> <!-- implicitly: - <struct name="chapter" isRoot="false" cardinality="*" + <struct name="chapter" isRoot="false" cardinality="{*}" transparent="false" isa="" attributesDescriptor=""> --> <field> @@ -52,7 +52,7 @@ </struct> <struct name="section"> <!-- implicitly: - <struct name="section" isRoot="false" cardinality="*" + <struct name="section" isRoot="false" cardinality="{*}" transparent="false" isa="" attributesDescriptor=""> --> <field> @@ -65,7 +65,7 @@ </struct> <struct name="subsection"> <!-- implicitly: - <struct name="subsection" isRoot="false" cardinality="*" + <struct name="subsection" isRoot="false" cardinality="{*}" transparent="false" isa="" attributesDescriptor=""> --> <field> @@ -77,7 +77,7 @@ </struct> <struct name="paragraph" transparent="true" role="paragraph"> <!-- implicitly: - <struct name="subsection" isRoot="false" cardinality="*" + <struct name="subsection" isRoot="false" cardinality="{*}" transparent="true" isa="" attributesDescriptor=""> --> <field> @@ -89,7 +89,7 @@ </struct> <struct name="text" transparent="true" role="text"> <!-- implicitly: - <struct name="text" isRoot="false" cardinality="*" + <struct name="text" isRoot="false" cardinality="{*}" transparent="true" isa="" attributesDescriptor=""> --> <!-- we might want to specify std.string here --> 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 @@ +<?xml version="1.0" standalone="yes"?> +<domain name="headings"> + + <import rel="domain" src="./book_domain.oxm"/> + + <struct name="heading" cardinality="{0-1}" transparent="true"> + <!-- The parent mechanism is a curious thing. Remind yourself + that parent-child-relationship in this sense are mediated + by fields. So we must either reference a field that is + already there or declare a new one on the fly. --> + <parent name="book.book"> + <field name="heading" isSubtree="true"/> + </parent> + <parent name="book.chapter"> + <field name="heading" isSubtree="true"/> + </parent> + <parent name="book.section"> + <field name="heading" isSubtree="true"/> + </parent> + <parent name="book.subsection"> + <field name="heading" isSubtree="true"/> + </parent> + <parent name="book.paragraph"> + <field name="heading" isSubtree="true"/> + </parent> + <!-- regarding its fields we have a problem here. We do not want to + declare a new field, because in fact we want to allow every + bit of content that a paragraph would allow - also considering + possible extensions of paragraph by other domains. + So we need to reference the default field of paragraph. --> + <fieldRef name="book.paragraph."/> + </struct> +</domain> |