summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core/model/Document.hpp4
-rw-r--r--src/core/model/Domain.hpp8
-rw-r--r--src/core/model/Node.cpp74
-rw-r--r--src/core/model/Node.hpp49
-rw-r--r--src/core/model/Typesystem.cpp16
-rw-r--r--src/core/model/Typesystem.hpp4
-rw-r--r--src/core/parser/ParserContext.cpp2
-rw-r--r--src/core/parser/ParserContext.hpp12
-rw-r--r--src/core/parser/ParserScope.cpp14
-rw-r--r--src/core/parser/ParserScope.hpp43
-rw-r--r--src/core/resource/ResourceManager.cpp23
-rw-r--r--src/core/resource/ResourceManager.hpp4
-rw-r--r--src/plugins/xml/XmlParser.cpp157
13 files changed, 330 insertions, 80 deletions
diff --git a/src/core/model/Document.hpp b/src/core/model/Document.hpp
index 1f2fb37..dcb8966 100644
--- a/src/core/model/Document.hpp
+++ b/src/core/model/Document.hpp
@@ -849,7 +849,7 @@ public:
/**
* Adds a Domain reference to this Document.
*/
- void addDomain(Handle<Domain> d)
+ void referenceDomain(Handle<Domain> d)
{
invalidate();
domains.push_back(d);
@@ -858,7 +858,7 @@ public:
/**
* Adds multiple Domain references to this Document.
*/
- void addDomains(const std::vector<Handle<Domain>> &d)
+ void referenceDomains(const std::vector<Handle<Domain>> &d)
{
invalidate();
domains.insert(domains.end(), d.begin(), d.end());
diff --git a/src/core/model/Domain.hpp b/src/core/model/Domain.hpp
index 541a428..cd649d5 100644
--- a/src/core/model/Domain.hpp
+++ b/src/core/model/Domain.hpp
@@ -899,8 +899,6 @@ class Domain : public Node {
private:
NodeVector<StructuredClass> structuredClasses;
NodeVector<AnnotationClass> annotationClasses;
- // TODO: Is it wise to attach the type systems here? If not: What would be
- // a good alternative.
NodeVector<Typesystem> typesystems;
protected:
@@ -937,7 +935,7 @@ public:
Domain(Manager &mgr, Handle<SystemTypesystem> sys, std::string name = "")
: Domain(mgr, std::move(name))
{
- includeTypesystem(sys);
+ referenceTypesystem(sys);
}
/**
@@ -1071,12 +1069,12 @@ public:
/**
* Adds a Typesystem reference to this Domain.
*/
- void includeTypesystem(Handle<Typesystem> t) { typesystems.push_back(t); }
+ void referenceTypesystem(Handle<Typesystem> t) { typesystems.push_back(t); }
/**
* Adds multiple Typesystem references to this Domain.
*/
- void includeTypesystems(const std::vector<Handle<Typesystem>> &ts)
+ void referenceTypesystems(const std::vector<Handle<Typesystem>> &ts)
{
typesystems.insert(typesystems.end(), ts.begin(), ts.end());
}
diff --git a/src/core/model/Node.cpp b/src/core/model/Node.cpp
index dbc85e2..3b5f38c 100644
--- a/src/core/model/Node.cpp
+++ b/src/core/model/Node.cpp
@@ -361,26 +361,92 @@ bool Node::checkDuplicate(Handle<Node> elem,
const std::string &name = elem->getName();
if (!names.emplace(name).second) {
logger.error(std::string("Element with name \"") + name +
- std::string("\" defined multiple times in parent ") +
- type().name + std::string(" \"") +
- Utils::join(path(), ".") + std::string("\""), *elem);
+ std::string("\" defined multiple times in parent ") +
+ type().name + std::string(" \"") +
+ Utils::join(path(), ".") + std::string("\""),
+ *elem);
return false;
}
return true;
}
+bool Node::checkIsAcyclic(std::vector<const Node *> &path,
+ std::unordered_set<const Node *> &visited,
+ NodeReferenceCallback callback) const
+{
+ // Add this node to the path
+ path.push_back(this);
+
+ // A cycle was found, abort, shorten the path to the actual cycle
+ if (visited.count(this)) {
+ return false;
+ }
+ visited.insert(this);
+
+ // Continue allong the path
+ const Node *node = callback(this);
+ if (node != nullptr) {
+ if (!node->checkIsAcyclic(path, visited, callback)) {
+ return false;
+ }
+ }
+
+ // Remove this node from the path
+ path.pop_back();
+ return true;
+}
+
bool Node::doValidate(Logger &logger) const { return true; }
bool Node::validateName(Logger &logger) const
{
if (!Utils::isIdentifier(name)) {
logger.error(type().name + std::string(" name \"") + name +
- std::string("\" is not a valid identifier"), this);
+ std::string("\" is not a valid identifier"),
+ this);
return false;
}
return true;
}
+bool Node::validateIsAcyclic(const std::string &name,
+ NodeReferenceCallback callback,
+ Logger &logger) const
+{
+ std::vector<const Node *> path;
+ std::unordered_set<const Node *> visited;
+
+ if (!checkIsAcyclic(path, visited, callback)) {
+ logger.error(std::string("Attribute \"") + name + ("\" is cyclic."),
+ this);
+ logger.note("The following nodes are included in the cycle: ",
+ SourceLocation{}, MessageMode::NO_CONTEXT);
+ for (const Node *node : path) {
+ const std::string &name = node->getName();
+ const std::string &typeName = node->type().name;
+ if (name.empty()) {
+ logger.note(std::string("Node of internal type ") + typeName +
+ std::string(" declared here:"),
+ node);
+ } else {
+ logger.note(std::string("Node \"") + name +
+ std::string("\" of internal type ") + typeName +
+ std::string(" declared here:"),
+ node);
+ }
+ }
+ return false;
+ }
+ return true;
+}
+
+bool Node::validateParentIsAcyclic(Logger &logger) const
+{
+ return validateIsAcyclic("parent", [](const Node *thisRef) -> const Node *
+ { return thisRef->parent.get(); },
+ logger);
+}
+
void Node::invalidate()
{
// Only perform the invalidation if necessary
diff --git a/src/core/model/Node.hpp b/src/core/model/Node.hpp
index 60d22e0..036bcae 100644
--- a/src/core/model/Node.hpp
+++ b/src/core/model/Node.hpp
@@ -31,8 +31,8 @@
#include <cstdint>
#include <map>
#include <set>
-#include <unordered_set>
#include <string>
+#include <unordered_set>
#include <vector>
#include <core/common/Location.hpp>
@@ -155,6 +155,7 @@ private:
* vector.
*
* @param p is the list the path should be constructed in.
+ * @param root is a node at which building the path should be aborted.
*/
void path(std::vector<std::string> &p, Handle<Node> root) const;
@@ -215,6 +216,30 @@ private:
std::unordered_set<std::string> &names,
Logger &logger) const;
+ /**
+ * Callback function used to access a Node reference stored inside another
+ * Node.
+ *
+ * @param thisRef is the Node of which the reference should be returned.
+ * @return the value of the reference.
+ */
+ using NodeReferenceCallback = const Node* (const Node* thisRef);
+
+ /**
+ * Checks whether the a certain property is acyclic.
+ *
+ * @param path is a path containing the cycle. If no cycle is found, the
+ * path will be empty.
+ * @param visited a set of visited nodes used for cycle detection.
+ * @param callback is the callback that is used to access the underlying
+ * property that should be checked for acyclicity.
+ * @return true if the node is acyclic regarding this property, false if
+ * a cycle was detected. The cycle is stored in the "path".
+ */
+ bool checkIsAcyclic(std::vector<const Node *> &path,
+ std::unordered_set<const Node *> &visited,
+ NodeReferenceCallback callback) const;
+
protected:
/**
* Sets the parent node.
@@ -365,6 +390,28 @@ protected:
bool validateName(Logger &logger) const;
/**
+ * Makes sure the property accessed by the callback is not cyclic.
+ *
+ * @param name is the name of the property. The passed name is used to build
+ * a nice error message.
+ * @param callback is the callback that is used to access the property.
+ * @param logger is the logger instance to which an error message containing
+ * the cycle is logged.
+ * @return true if the parent reference is acyclic, false otherwise.
+ */
+ bool validateIsAcyclic(const std::string &name,
+ NodeReferenceCallback callback, Logger &logger) const;
+
+ /**
+ * Makes sure the "parent" reference is not cyclic.
+ *
+ * @param logger is the logger instance to which an error message containing
+ * the cycle is logged.
+ * @return true if the parent reference is acyclic, false otherwise.
+ */
+ bool validateParentIsAcyclic(Logger &logger) const;
+
+ /**
* Helper function that can be used to forward the validation process to
* child nodes.
*
diff --git a/src/core/model/Typesystem.cpp b/src/core/model/Typesystem.cpp
index 5f8f613..c10fc02 100644
--- a/src/core/model/Typesystem.cpp
+++ b/src/core/model/Typesystem.cpp
@@ -383,6 +383,11 @@ bool StructType::doBuild(Variant &data, Logger &logger) const
bool StructType::doValidate(Logger &logger) const
{
return validateName(logger) &
+ validateIsAcyclic("parent", [](const Node *thisRef) -> const Node * {
+ return dynamic_cast<const StructType *>(
+ thisRef)->parentStructure.get();
+ },
+ logger) &
continueValidationCheckDuplicates(attributes, logger);
}
@@ -542,7 +547,7 @@ Rooted<StructType> Typesystem::createStructType(const std::string &name)
return structType;
}
-void Typesystem::includeTypesystem(Handle<Typesystem> typesystem)
+void Typesystem::referenceTypesystem(Handle<Typesystem> typesystem)
{
typesystems.push_back(typesystem);
}
@@ -573,8 +578,9 @@ const Rtti DoubleType =
RttiBuilder<ousia::DoubleType>("DoubleType").parent(&Type);
const Rtti BoolType = RttiBuilder<ousia::BoolType>("BoolType").parent(&Type);
const Rtti EnumType = RttiBuilder<ousia::EnumType>("EnumType").parent(&Type);
-const Rtti StructType =
- RttiBuilder<ousia::StructType>("StructType").parent(&Type).composedOf(&Attribute);
+const Rtti StructType = RttiBuilder<ousia::StructType>("StructType")
+ .parent(&Type)
+ .composedOf(&Attribute);
const Rtti ArrayType = RttiBuilder<ousia::ArrayType>("ArrayType").parent(&Type);
const Rtti UnknownType =
RttiBuilder<ousia::UnknownType>("UnknownType").parent(&Type);
@@ -584,8 +590,8 @@ const Rtti Typesystem =
RttiBuilder<ousia::Typesystem>("Typesystem").parent(&Node).composedOf(
{&StringType, &IntType, &DoubleType, &BoolType, &EnumType, &StructType,
&Constant});
-const Rtti SystemTypesystem =
- RttiBuilder<ousia::SystemTypesystem> ("SystemTypesystem").parent(&Typesystem);
+const Rtti SystemTypesystem = RttiBuilder<ousia::SystemTypesystem>(
+ "SystemTypesystem").parent(&Typesystem);
}
}
diff --git a/src/core/model/Typesystem.hpp b/src/core/model/Typesystem.hpp
index 1405ed6..e06938e 100644
--- a/src/core/model/Typesystem.hpp
+++ b/src/core/model/Typesystem.hpp
@@ -989,7 +989,7 @@ public:
Typesystem(Manager &mgr, Handle<SystemTypesystem> sys, std::string name)
: Typesystem(mgr, std::move(name))
{
- includeTypesystem(sys);
+ referenceTypesystem(sys);
}
/**
@@ -1007,7 +1007,7 @@ public:
* @param typesystem is the typesystem that should be added to the
* referenced typesystems list.
*/
- void includeTypesystem(Handle<Typesystem> typesystem);
+ void referenceTypesystem(Handle<Typesystem> typesystem);
/**
* Adds the given type to the to the type list.
diff --git a/src/core/parser/ParserContext.cpp b/src/core/parser/ParserContext.cpp
index b4e2a9a..14b02df 100644
--- a/src/core/parser/ParserContext.cpp
+++ b/src/core/parser/ParserContext.cpp
@@ -39,7 +39,7 @@ ParserContext::ParserContext(Registry &registry,
{
}
-NodeVector<Node> ParserContext::import(const std::string &path,
+Rooted<Node> ParserContext::import(const std::string &path,
const std::string mimetype,
const std::string rel,
const RttiSet &supportedTypes)
diff --git a/src/core/parser/ParserContext.hpp b/src/core/parser/ParserContext.hpp
index 2787225..1b889b1 100644
--- a/src/core/parser/ParserContext.hpp
+++ b/src/core/parser/ParserContext.hpp
@@ -117,8 +117,8 @@ public:
* checked, not the actual result.
* @return the parsed node or nullptr if something goes wrong.
*/
- NodeVector<Node> import(const std::string &path, const std::string mimetype,
- const std::string rel, const RttiSet &supportedTypes);
+ Rooted<Node> import(const std::string &path, const std::string mimetype,
+ const std::string rel, const RttiSet &supportedTypes);
/**
* Parses a file with ParserContext and the current ParserScope. In contrast
@@ -136,10 +136,12 @@ public:
* @param supportedTypes contains the types of the returned Node the caller
* can deal with. Note that only the types the parser claims to return are
* checked, not the actual result.
- * @return the parsed node or nullptr if something goes wrong.
+ * @return the parsed nodes or an empty list if something goes wrong (or
+ * there were indeed no objects to be parsed).
*/
- NodeVector<Node> include(const std::string &path, const std::string mimetype,
- const std::string rel, const RttiSet &supportedTypes);
+ NodeVector<Node> include(const std::string &path,
+ const std::string mimetype, const std::string rel,
+ const RttiSet &supportedTypes);
/**
* Clones the ParserContext instance but exchanges the ParserScope instance
diff --git a/src/core/parser/ParserScope.cpp b/src/core/parser/ParserScope.cpp
index 0e2350f..3d1ba78 100644
--- a/src/core/parser/ParserScope.cpp
+++ b/src/core/parser/ParserScope.cpp
@@ -168,6 +168,20 @@ Rooted<Node> ParserScope::getRoot() const { return nodes.front(); }
Rooted<Node> ParserScope::getLeaf() const { return nodes.back(); }
+Rooted<Node> ParserScope::select(RttiSet types, int maxDepth)
+{
+ ssize_t minDepth = 0;
+ if (maxDepth >= 0) {
+ minDepth = static_cast<ssize_t>(nodes.size()) - (maxDepth + 1);
+ }
+ for (ssize_t i = nodes.size() - 1; i >= minDepth; i--) {
+ if (nodes[i]->type().isOneOf(types)) {
+ return nodes[i];
+ }
+ }
+ return nullptr;
+}
+
void ParserScope::setFlag(ParserFlag flag, bool value)
{
// Fetch the current stack depth
diff --git a/src/core/parser/ParserScope.hpp b/src/core/parser/ParserScope.hpp
index 2c6093f..1191cbc 100644
--- a/src/core/parser/ParserScope.hpp
+++ b/src/core/parser/ParserScope.hpp
@@ -324,14 +324,24 @@ public:
/**
* Returns the bottom-most Node instance in the ParserScope hirarchy, e.g.
- *the
- * node that was pushed last onto the stack.
+ * the node that was pushed last onto the stack.
*
* @return a reference at the leaf node.
*/
Rooted<Node> getLeaf() const;
/**
+ * Ascends in the stack starting with the leaf node, returns the first node
+ * that matches the type given in the RttiSet or nullptr if none matches.
+ *
+ * @param types is a set of Rtti types for which should be searched in the
+ * stack.
+ * @param maxDepth is the maximum number of stack entries the selection
+ * function may ascend. A negative value indicates no limitation.
+ */
+ Rooted<Node> select(RttiSet types, int maxDepth = -1);
+
+ /**
* Sets a parser flag for the current stack depth.
*
* @param flag is the flag that should be set.
@@ -353,12 +363,10 @@ public:
* Tries to resolve a node for the given type and path for all nodes
* currently on the stack, starting with the topmost node on the stack.
* Calls the "imposterCallback" function for obtaining a temporary
- *result if
- * a node cannot be resolved right now. The "resultCallback" is at most
- * called twice: Once when this method is called (probably with the
+ * result if a node cannot be resolved right now. The "resultCallback" is
+ * at most called twice: Once when this method is called (probably with the
* temporary) and another time if the resolution turned out to be
- *successful
- * at a later point in time.
+ * successful at a later point in time.
*
* @param path is the path for which a node should be resolved.
* @param type is the type of the node that should be resolved.
@@ -367,24 +375,17 @@ public:
* @param imposterCallback is the callback function that is called if
* the node cannot be resolved at this moment. It gives the caller the
* possibility to create an imposter (a temporary object) that may be
- *used
- * later in the resolution process.
+ * used later in the resolution process.
* @param resultCallback is the callback function to which the result of
* the resolution process is passed. This function is called at least
- *once
- * either with the imposter (if the resolution was not successful) or
- *the
- * resolved object directly when this function is called. If the
- *resolution
- * was not successful the first time, it may be called another time
- *later
- * in the context of the "performDeferredResolution" function.
+ * once either with the imposter (if the resolution was not successful) or
+ * the resolved object directly when this function is called. If the
+ * resolution was not successful the first time, it may be called another
+ * time later in the context of the "performDeferredResolution" function.
* @param location is the location in the current source file in which
- *the
- * resolution was triggered.
+ * the resolution was triggered.
* @return true if the resolution was immediately successful. This does
- *not
- * mean, that the resolved object does not exist, as it may be resolved
+ * not mean, that the resolved object does not exist, as it may be resolved
* later.
*/
bool resolve(const std::vector<std::string> &path, const Rtti &type,
diff --git a/src/core/resource/ResourceManager.cpp b/src/core/resource/ResourceManager.cpp
index 2484cb2..1d32a4d 100644
--- a/src/core/resource/ResourceManager.cpp
+++ b/src/core/resource/ResourceManager.cpp
@@ -122,8 +122,12 @@ NodeVector<Node> ResourceManager::parse(
innerScope.checkUnwound(logger);
innerScope.performDeferredResolution(logger);
- // Fetch the nodes that were parsed by this parser instance
+ // Fetch the nodes that were parsed by this parser instance and
+ // validate them
parsedNodes = innerScope.getTopLevelNodes();
+ for (auto parsedNode : parsedNodes) {
+ parsedNode->validate(logger);
+ }
// Make sure the number of elements is exactly one -- we can
// only store one element per top-level node.
@@ -184,13 +188,18 @@ NodeVector<Node> ResourceManager::parse(
return parsedNodes;
}
-NodeVector<Node> ResourceManager::import(ParserContext &ctx,
- const std::string &path,
- const std::string &mimetype,
- const std::string &rel,
- const RttiSet &supportedTypes)
+Rooted<Node> ResourceManager::import(ParserContext &ctx,
+ const std::string &path,
+ const std::string &mimetype,
+ const std::string &rel,
+ const RttiSet &supportedTypes)
{
- return parse(ctx, path, mimetype, rel, supportedTypes, ParseMode::IMPORT);
+ NodeVector<Node> res =
+ parse(ctx, path, mimetype, rel, supportedTypes, ParseMode::IMPORT);
+ if (res.size() == 1U) {
+ return res[0];
+ }
+ return nullptr;
}
NodeVector<Node> ResourceManager::include(ParserContext &ctx,
diff --git a/src/core/resource/ResourceManager.hpp b/src/core/resource/ResourceManager.hpp
index 83556aa..1279bee 100644
--- a/src/core/resource/ResourceManager.hpp
+++ b/src/core/resource/ResourceManager.hpp
@@ -158,9 +158,9 @@ public:
* @param supportedTypes contains the types of the returned Node the caller
* can deal with. Note that only the types the parser claims to return are
* checked, not the actual result.
- * @return the parsed nodes or an empty list if something went wrong.
+ * @return the parsed node or nullptr if something went wrong.
*/
- NodeVector<Node> import(ParserContext &ctx, const std::string &path,
+ Rooted<Node> import(ParserContext &ctx, const std::string &path,
const std::string &mimetype, const std::string &rel,
const RttiSet &supportedTypes);
diff --git a/src/plugins/xml/XmlParser.cpp b/src/plugins/xml/XmlParser.cpp
index 51c52bc..d71ceac 100644
--- a/src/plugins/xml/XmlParser.cpp
+++ b/src/plugins/xml/XmlParser.cpp
@@ -22,34 +22,103 @@
#include <expat.h>
#include <core/common/CharReader.hpp>
+#include <core/common/RttiBuilder.hpp>
#include <core/common/Utils.hpp>
#include <core/common/VariantReader.hpp>
#include <core/parser/ParserStack.hpp>
#include <core/parser/ParserScope.hpp>
+#include <core/model/Document.hpp>
+#include <core/model/Domain.hpp>
+#include <core/model/Project.hpp>
#include <core/model/Typesystem.hpp>
#include "XmlParser.hpp"
namespace ousia {
-/* Document structure */
-static const State STATE_DOCUMENT = 0;
-static const State STATE_HEAD = 1;
-static const State STATE_BODY = 2;
+/* HeadNode Helper class */
-/* Special commands */
-static const State STATE_USE = 100;
-static const State STATE_INCLUDE = 101;
-static const State STATE_INLINE = 102;
+namespace {
+class HeadNode : public Node {
+public:
+ using Node::Node;
+};
+}
-/* Type system definitions */
-static const State STATE_TYPESYSTEM = 200;
-static const State STATE_TYPES = 201;
-static const State STATE_CONSTANTS = 202;
-static const State STATE_CONSTANT = 203;
-static const State STATE_ENUM = 204;
-static const State STATE_STRUCT = 205;
-static const State STATE_FIELD = 206;
+namespace RttiTypes {
+static Rtti HeadNode = RttiBuilder<ousia::HeadNode>("HeadNode");
+}
+
+/* Element Handler Classes */
+
+class DocumentHandler : public Handler {
+public:
+ using Handler::Handler;
+
+ void start(Variant::mapType &args) override
+ {
+ Rooted<Document> document =
+ project()->createDocument(args["name"].asString());
+ document->setLocation(location());
+ scope().push(document);
+ scope().setFlag(ParserFlag::POST_HEAD, false);
+ }
+
+ void end() override { scope().pop(); }
+
+ static Handler *create(const HandlerData &handlerData)
+ {
+ return new DocumentHandler{handlerData};
+ }
+};
+
+class HeadHandler : public Handler {
+public:
+ using Handler::Handler;
+
+ void start(Variant::mapType &args) override
+ {
+ // Make sure the "HEAD" node is actually allowed here
+ if (scope().getFlag(ParserFlag::POST_HEAD)) {
+ throw LoggableException{
+ "\"head\" tag not allowed here, head was already specified or "
+ "another command was given first",
+ location()};
+ }
+
+ // Insert a new HeadNode instance
+ scope().push(new HeadNode{manager()});
+ }
+
+ void end() override
+ {
+ // Remove the HeadNode instance from the stack
+ scope().pop();
+ scope().setFlag(ParserFlag::POST_HEAD, true);
+ }
+
+ static Handler *create(const HandlerData &handlerData)
+ {
+ return new HeadHandler{handlerData};
+ }
+};
+
+class DisableHeadHandler : public Handler {
+public:
+ using Handler::Handler;
+
+ void start(Variant::mapType &args) override
+ {
+ scope().setFlag(ParserFlag::POST_HEAD, true);
+ }
+
+ void end() override {}
+
+ static Handler *create(const HandlerData &handlerData)
+ {
+ return new DisableHeadHandler{handlerData};
+ }
+};
class TypesystemHandler : public Handler {
public:
@@ -57,10 +126,20 @@ public:
void start(Variant::mapType &args) override
{
+ // Create the typesystem instance
Rooted<Typesystem> typesystem =
project()->createTypesystem(args["name"].asString());
typesystem->setLocation(location());
+
+ // Check whether this typesystem is a direct child of a domain
+ Handle<Node> parent = scope().select({&RttiTypes::Domain});
+ if (parent != nullptr) {
+ parent.cast<Domain>()->referenceTypesystem(typesystem);
+ }
+
+ // Push the typesystem onto the scope, set the POST_HEAD flag to true
scope().push(typesystem);
+ scope().setFlag(ParserFlag::POST_HEAD, false);
}
void end() override { scope().pop(); }
@@ -148,25 +227,52 @@ public:
}
};
+/* Document structure */
+static const State STATE_DOCUMENT = 0;
+static const State STATE_DOCUMENT_HEAD = 1;
+
+/* Special commands */
+static const State STATE_IMPORT = 100;
+static const State STATE_INCLUDE = 101;
+
+/* Type system definitions */
+static const State STATE_TYPESYSTEM = 200;
+static const State STATE_TYPESYSTEM_HEAD = 201;
+static const State STATE_TYPES = 202;
+static const State STATE_CONSTANTS = 203;
+static const State STATE_CONSTANT = 204;
+static const State STATE_ENUM = 205;
+static const State STATE_STRUCT = 206;
+static const State STATE_FIELD = 207;
+
+/* Domain definitions */
+static const State STATE_DOMAIN = 300;
+static const State STATE_DOMAIN_HEAD = 301;
+
static const std::multimap<std::string, HandlerDescriptor> XML_HANDLERS{
/* Document tags */
- {"document", {{STATE_NONE}, nullptr, STATE_DOCUMENT}},
- {"head", {{STATE_DOCUMENT}, nullptr, STATE_HEAD}},
- {"body", {{STATE_DOCUMENT}, nullptr, STATE_BODY, true}},
+ {"document",
+ {{STATE_NONE},
+ DocumentHandler::create,
+ STATE_DOCUMENT,
+ true,
+ {Argument::String("name", "")}}},
+ {"head", {{STATE_DOCUMENT}, HeadHandler::create, STATE_DOCUMENT_HEAD}},
/* Special commands */
- {"use", {{STATE_HEAD}, nullptr, STATE_USE}},
+ {"import",
+ {{STATE_DOCUMENT_HEAD, STATE_TYPESYSTEM_HEAD}, nullptr, STATE_IMPORT}},
{"include", {{STATE_ALL}, nullptr, STATE_INCLUDE}},
- {"inline", {{STATE_ALL}, nullptr, STATE_INLINE}},
/* Typesystem */
{"typesystem",
- {{STATE_NONE, STATE_HEAD},
+ {{STATE_NONE, STATE_DOMAIN_HEAD},
TypesystemHandler::create,
STATE_TYPESYSTEM,
false,
{Argument::String("name")}}},
- {"types", {{STATE_TYPESYSTEM}, nullptr, STATE_TYPES}},
+ {"head", {{STATE_TYPESYSTEM}, HeadHandler::create, STATE_TYPESYSTEM}},
+ {"types", {{STATE_TYPESYSTEM}, DisableHeadHandler::create, STATE_TYPES}},
{"enum", {{STATE_TYPES}, nullptr, STATE_ENUM}},
{"struct",
{{STATE_TYPES},
@@ -175,13 +281,14 @@ static const std::multimap<std::string, HandlerDescriptor> XML_HANDLERS{
false,
{Argument::String("name"), Argument::String("parent", "")}}},
{"field",
- {{{STATE_STRUCT}},
+ {{STATE_STRUCT},
StructFieldHandler::create,
STATE_FIELD,
false,
{Argument::String("name"), Argument::String("type"),
Argument::Any("default", Variant::fromObject(nullptr))}}},
- {"constants", {{STATE_TYPESYSTEM}, nullptr, STATE_CONSTANTS}},
+ {"constants",
+ {{STATE_TYPESYSTEM}, DisableHeadHandler::create, STATE_CONSTANTS}},
{"constant", {{STATE_CONSTANTS}, nullptr, STATE_CONSTANT}}};
/**