summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/plugins/xml/XmlParser.cpp128
-rw-r--r--test/plugins/xml/XmlParserTest.cpp29
-rw-r--r--testdata/xmlparser/book_domain.oxm98
3 files changed, 242 insertions, 13 deletions
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> domain = scope().select<Domain>();
Rooted<StructuredClass> 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<StructuredClass>(
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<Descriptor> parent = scope().select<Descriptor>();
+
+ Rooted<FieldDescriptor> 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<Descriptor> parent = scope().select<Descriptor>();
+
+ Rooted<FieldDescriptor> field = parent->createPrimitiveFieldDescriptor(
+ nullptr, args["name"].asString(), args["optional"].asBool());
+ field->setLocation(location());
+
+ const std::string &type = args["type"].asString();
+ scope().resolve<Type>(
+ type, field, logger(),
+ [](Handle<Node> type, Handle<Node> field, Logger &logger) {
+ if (type != nullptr) {
+ field.cast<FieldDescriptor>()->setPrimitiveType(
+ type.cast<Type>());
+ }
+ });
+
+ 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<FieldDescriptor> field = scope().select<FieldDescriptor>();
+
+ const std::string &ref = args["ref"].asString();
+ scope().resolve<StructuredClass>(
+ ref, field, logger(),
+ [](Handle<Node> child, Handle<Node> field, Logger &logger) {
+ if (child != nullptr) {
+ field.cast<FieldDescriptor>()->addChild(
+ child.cast<StructuredClass>());
+ }
+ });
+ }
+
+ 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<std::string, const ParserState *> 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 <core/common/CharReader.hpp>
#include <core/common/SourceContextReader.hpp>
+#include <core/model/Domain.hpp>
#include <core/model/Project.hpp>
#include <core/frontend/TerminalLogger.hpp>
#include <core/StandaloneEnvironment.hpp>
@@ -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<Node> n =
+ env.parse("book_domain.oxm", "", "", RttiSet{&RttiTypes::Domain});
+ ASSERT_FALSE(n.isNull());
+ // check the domain node.
+ Rooted<Domain> domain = n.cast<Domain>();
+ ASSERT_EQ("book", domain->getName());
+ // get the book struct node.
+ auto res = domain->resolve(RttiTypes::StructuredClass, "book");
+ ASSERT_EQ(1, res.size());
+ Rooted<StructuredClass> bookStruct = res[0].node.cast<StructuredClass>();
+ 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 @@
+<?xml version="1.0"?>
+<!-- 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
+ a context free grammar, which specifies the language of documents that
+ may be constructed using this domain. Note that this grammar may be
+ influenced by other domains depending on this one. -->
+ <!-- Note that we specify neither attributes,
+ 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">
+ <!-- implicitly:
+ <struct name="book" cardinality="1" isRoot="true"
+ transparent="false" isa="" attributesDescriptor="">
+ -->
+ <!-- Note that we assume that, if not specified, a
+ field is assumed to have no name, be of type TREE
+ and not optional. -->
+ <field>
+ <!-- implicitly:
+ <field name="" isSubtree="false" optional="false">
+ -->
+ <!-- Using such child references might be problematic if
+ multiple nodes are matched. This should probably
+ result in an exception.
+ Also note that we only reference the child classes.
+ We do _not_ declare them here. This might lead to
+ some difficulties in the parsing process as I
+ effectively use forward declarations here. So the
+ resolve() process may only be started _after_ all
+ delcarations are read. -->
+ <child ref="book.chapter"/>
+ <!-- The dot notation as path separator might be changed
+ but I think it to be intuitive. If we want a more
+ CSS like style we can use whitespaces here. -->
+ <child ref="book.paragraph"/>
+ </field>
+ </struct>
+ <struct name="chapter">
+ <!-- implicitly:
+ <struct name="chapter" isRoot="false" cardinality="*"
+ transparent="false" isa="" attributesDescriptor="">
+ -->
+ <field>
+ <!-- implicitly:
+ <field name="" isSubtree="false" optional="false">
+ -->
+ <child ref="book.section"/>
+ <child ref="book.paragraph"/>
+ </field>
+ </struct>
+ <struct name="section">
+ <!-- implicitly:
+ <struct name="section" isRoot="false" cardinality="*"
+ transparent="false" isa="" attributesDescriptor="">
+ -->
+ <field>
+ <!-- implicitly:
+ <field name="" isSubtree="false" optional="false">
+ -->
+ <child ref="book.subsection"/>
+ <child ref="book.paragraph"/>
+ </field>
+ </struct>
+ <struct name="subsection">
+ <!-- implicitly:
+ <struct name="subsection" isRoot="false" cardinality="*"
+ transparent="false" isa="" attributesDescriptor="">
+ -->
+ <field>
+ <!-- implicitly:
+ <field name="" isSubtree="false" optional="false">
+ -->
+ <child ref="book.paragraph"/>
+ </field>
+ </struct>
+ <struct name="paragraph" transparent="true" role="paragraph">
+ <!-- implicitly:
+ <struct name="subsection" isRoot="false" cardinality="*"
+ transparent="true" isa="" attributesDescriptor="">
+ -->
+ <field>
+ <!-- implicitly:
+ <field name="" type="TREE" optional="false">
+ -->
+ <child ref="book.text"/>
+ </field>
+ </struct>
+ <struct name="text" transparent="true" role="text">
+ <!-- implicitly:
+ <struct name="text" isRoot="false" cardinality="*"
+ transparent="true" isa="" attributesDescriptor="">
+ -->
+ <!-- we might want to specify std.string here -->
+ <primitive name="content" type="string"/>
+ </struct>
+</domain>