summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt4
-rw-r--r--src/core/parser/stack/DocumentHandler.cpp252
-rw-r--r--src/core/parser/stack/DocumentHandler.hpp88
-rw-r--r--src/core/parser/stack/DomainHandler.cpp276
-rw-r--r--src/core/parser/stack/DomainHandler.hpp200
-rw-r--r--src/core/parser/stack/Handler.cpp2
-rw-r--r--src/core/parser/stack/ImportIncludeHandler.cpp96
-rw-r--r--src/core/parser/stack/ImportIncludeHandler.hpp90
-rw-r--r--src/core/parser/stack/TypesystemHandler.cpp175
-rw-r--r--src/core/parser/stack/TypesystemHandler.hpp121
10 files changed, 1303 insertions, 1 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 4f9a8d3..4a3db32 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -163,9 +163,13 @@ ADD_LIBRARY(ousia_core
src/core/parser/ParserContext
src/core/parser/ParserScope
src/core/parser/stack/Callbacks
+ src/core/parser/stack/DocumentHandler
+ src/core/parser/stack/DomainHandler
src/core/parser/stack/Handler
+ src/core/parser/stack/ImportIncludeHandler
src/core/parser/stack/State
src/core/parser/stack/Stack
+ src/core/parser/stack/TypesystemHandler
src/core/parser/utils/Tokenizer
src/core/parser/utils/TokenTrie
src/core/resource/Resource
diff --git a/src/core/parser/stack/DocumentHandler.cpp b/src/core/parser/stack/DocumentHandler.cpp
new file mode 100644
index 0000000..ba7430d
--- /dev/null
+++ b/src/core/parser/stack/DocumentHandler.cpp
@@ -0,0 +1,252 @@
+/*
+ Ousía
+ Copyright (C) 2014, 2015 Benjamin Paaßen, Andreas Stöckel
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "DocumentHandler.hpp"
+
+#include <algorithm>
+
+#include <core/common/RttiBuilder.hpp>
+#include <core/common/Utils.hpp>
+#include <core/model/Document.hpp>
+#include <core/model/Domain.hpp>
+#include <core/model/Typesystem.hpp>
+#include <core/parser/ParserScope.hpp>
+
+namespace ousia {
+
+/* DocumentHandler */
+
+void DocumentHandler::start(Variant::mapType &args)
+{
+ Rooted<Document> document =
+ project()->createDocument(args["name"].asString());
+ document->setLocation(location());
+ scope().push(document);
+ scope().setFlag(ParserFlag::POST_HEAD, false);
+}
+
+void DocumentHandler::end() { scope().pop(); }
+
+/* DocumentChildHandler */
+
+void DocumentChildHandler::preamble(Handle<Node> parentNode,
+ std::string &fieldName,
+ DocumentEntity *&parent, bool &inField)
+{
+ // check if the parent in the structure tree was an explicit field
+ // reference.
+ inField = parentNode->isa(&RttiTypes::DocumentField);
+ if (inField) {
+ fieldName = parentNode->getName();
+ parentNode = scope().selectOrThrow(
+ {&RttiTypes::StructuredEntity, &RttiTypes::AnnotationEntity});
+ } else {
+ // if it wasn't an explicit reference, we use the default field.
+ fieldName = DEFAULT_FIELD_NAME;
+ }
+ // reference the parent entity explicitly.
+ parent = nullptr;
+ if (parentNode->isa(&RttiTypes::StructuredEntity)) {
+ parent = static_cast<DocumentEntity *>(
+ parentNode.cast<StructuredEntity>().get());
+ } else if (parentNode->isa(&RttiTypes::AnnotationEntity)) {
+ parent = static_cast<DocumentEntity *>(
+ parentNode.cast<AnnotationEntity>().get());
+ }
+}
+
+void DocumentChildHandler::createPath(const NodeVector<Node> &path,
+ DocumentEntity *&parent)
+{
+ size_t S = path.size();
+ for (size_t p = 1; p < S; p = p + 2) {
+ parent = static_cast<DocumentEntity *>(
+ parent->createChildStructuredEntity(
+ path[p].cast<StructuredClass>(), Variant::mapType{},
+ path[p - 1]->getName(), "").get());
+ }
+}
+
+void DocumentChildHandler::start(Variant::mapType &args)
+{
+ scope().setFlag(ParserFlag::POST_HEAD, true);
+ Rooted<Node> parentNode = scope().selectOrThrow(
+ {&RttiTypes::Document, &RttiTypes::StructuredEntity,
+ &RttiTypes::AnnotationEntity, &RttiTypes::DocumentField});
+
+ std::string fieldName;
+ DocumentEntity *parent;
+ bool inField;
+
+ preamble(parentNode, fieldName, parent, inField);
+
+ // try to find a FieldDescriptor for the given tag if we are not in a
+ // field already. This does _not_ try to construct transparent paths
+ // in between.
+ if (!inField && parent != nullptr &&
+ parent->getDescriptor()->hasField(name())) {
+ Rooted<DocumentField> field{
+ new DocumentField(parentNode->getManager(), fieldName, parentNode)};
+ field->setLocation(location());
+ scope().push(field);
+ return;
+ }
+
+ // Otherwise create a new StructuredEntity
+ // TODO: Consider Anchors and AnnotationEntities
+ Rooted<StructuredClass> strct =
+ scope().resolve<StructuredClass>(Utils::split(name(), ':'), logger());
+ if (strct == nullptr) {
+ // if we could not resolve the name, throw an exception.
+ throw LoggableException(
+ std::string("\"") + name() + "\" could not be resolved.",
+ location());
+ }
+
+ std::string name;
+ auto it = args.find("name");
+ if (it != args.end()) {
+ name = it->second.asString();
+ args.erase(it);
+ }
+
+ Rooted<StructuredEntity> entity;
+ if (parentNode->isa(&RttiTypes::Document)) {
+ entity = parentNode.cast<Document>()->createRootStructuredEntity(
+ strct, args, name);
+ } else {
+ // calculate a path if transparent entities are needed in between.
+ auto path = parent->getDescriptor()->pathTo(strct, logger());
+ if (path.empty()) {
+ throw LoggableException(
+ std::string("An instance of \"") + strct->getName() +
+ "\" is not allowed as child of an instance of \"" +
+ parent->getDescriptor()->getName() + "\"",
+ location());
+ }
+
+ // create all transparent entities until the last field.
+ createPath(path, parent);
+ entity =
+ parent->createChildStructuredEntity(strct, args, fieldName, name);
+ }
+ entity->setLocation(location());
+ scope().push(entity);
+}
+
+void DocumentChildHandler::end() { scope().pop(); }
+
+std::pair<bool, Variant> DocumentChildHandler::convertData(
+ Handle<FieldDescriptor> field, Logger &logger, const std::string &data)
+{
+ // if the content is supposed to be of type string, we can finish
+ // directly.
+ auto vts = field->getPrimitiveType()->getVariantTypes();
+ if (std::find(vts.begin(), vts.end(), VariantType::STRING) != vts.end()) {
+ return std::make_pair(true, Variant::fromString(data));
+ }
+
+ // then try to parse the content using the type specification.
+ auto res = field->getPrimitiveType()->read(
+ data, logger, location().getSourceId(), location().getStart());
+ return res;
+}
+
+void DocumentChildHandler::data(const std::string &data, int fieldIdx)
+{
+ Rooted<Node> parentNode = scope().selectOrThrow(
+ {&RttiTypes::StructuredEntity, &RttiTypes::AnnotationEntity,
+ &RttiTypes::DocumentField});
+
+ std::string fieldName;
+ DocumentEntity *parent;
+ bool inField;
+
+ preamble(parentNode, fieldName, parent, inField);
+
+ Rooted<Descriptor> desc = parent->getDescriptor();
+ /*
+ * We distinguish two cases here: One for fields that are given.
+ */
+ if (fieldName != DEFAULT_FIELD_NAME) {
+ // retrieve the actual FieldDescriptor
+ Rooted<FieldDescriptor> field = desc->getFieldDescriptor(fieldName);
+ if (field == nullptr) {
+ logger().error(
+ std::string("Can't handle data because no field with name \"") +
+ fieldName + "\" exists in descriptor\"" + desc->getName() +
+ "\".",
+ location());
+ return;
+ }
+ // if it is not primitive at all, we can't parse the content.
+ if (!field->isPrimitive()) {
+ logger().error(std::string("Can't handle data because field \"") +
+ fieldName + "\" of descriptor \"" +
+ desc->getName() + "\" is not primitive!",
+ location());
+ return;
+ }
+ // then try to parse the content using the type specification.
+ auto res = convertData(field, logger(), data);
+ // add it as primitive content.
+ if (res.first) {
+ parent->createChildDocumentPrimitive(res.second, fieldName);
+ }
+ } else {
+ /*
+ * The second case is for primitive fields. Here we search through
+ * all FieldDescriptors that allow primitive content at this point
+ * and could be constructed via transparent intermediate entities.
+ * We then try to parse the data using the type specified by the
+ * respective field. If that does not work we proceed to the next
+ * possible field.
+ */
+ // retrieve all fields.
+ NodeVector<FieldDescriptor> fields = desc->getDefaultFields();
+ std::vector<LoggerFork> forks;
+ for (auto field : fields) {
+ // then try to parse the content using the type specification.
+ forks.emplace_back(logger().fork());
+ auto res = convertData(field, forks.back(), data);
+ if (res.first) {
+ forks.back().commit();
+ // if that worked, construct the necessary path.
+ auto pathRes = desc->pathTo(field, logger());
+ assert(pathRes.second);
+ NodeVector<Node> path = pathRes.first;
+ createPath(path, parent);
+ // then create the primitive element.
+ parent->createChildDocumentPrimitive(res.second, fieldName);
+ return;
+ }
+ }
+ logger().error("Could not read data with any of the possible fields:");
+ for (size_t f = 0; f < fields.size(); f++) {
+ logger().note(Utils::join(fields[f]->path(), ".") + ":",
+ SourceLocation{}, MessageMode::NO_CONTEXT);
+ forks[f].commit();
+ }
+ }
+}
+
+namespace RttiTypes {
+const Rtti DocumentField =
+ RttiBuilder<ousia::DocumentField>("DocumentField").parent(&Node);
+}
+}
diff --git a/src/core/parser/stack/DocumentHandler.hpp b/src/core/parser/stack/DocumentHandler.hpp
new file mode 100644
index 0000000..475fe69
--- /dev/null
+++ b/src/core/parser/stack/DocumentHandler.hpp
@@ -0,0 +1,88 @@
+/*
+ Ousía
+ Copyright (C) 2014, 2015 Benjamin Paaßen, Andreas Stöckel
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file DocumentHandler.hpp
+ *
+ * @author Andreas Stöckel (astoecke@techfak.uni-bielefeld.de)
+ */
+
+#ifndef _OUSIA_DOCUMENT_HANDLER_HPP_
+#define _OUSIA_DOCUMENT_HANDLER_HPP_
+
+#include <core/common/Variant.hpp>
+
+#include "Handler.hpp"
+
+namespace ousia {
+
+// Forward declarations
+class Rtti;
+class DocumentEntity;
+class FieldDescriptor;
+
+class DocumentHandler : public StaticHandler {
+public:
+ using StaticHandler::StaticHandler;
+
+ bool start(Variant::mapType &args) override;
+
+ void end() override;
+
+ static Handler *create(const HandlerData &handlerData)
+ {
+ return new DocumentHandler{handlerData};
+ }
+};
+
+class DocumentField : public Node {
+public:
+ using Node::Node;
+};
+
+class DocumentChildHandler : public StaticHandler {
+private:
+ void preamble(Handle<Node> parentNode, std::string &fieldName,
+ DocumentEntity *&parent, bool &inField);
+
+ void createPath(const NodeVector<Node> &path, DocumentEntity *&parent);
+
+ std::pair<bool, Variant> convertData(Handle<FieldDescriptor> field,
+ Logger &logger,
+ const std::string &data);
+
+public:
+ using Handler::Handler;
+
+ bool start(Variant::mapType &args) override;
+
+ void end() override;
+
+ bool data(const Variant &data) override;
+
+ static Handler *create(const HandlerData &handlerData)
+ {
+ return new DocumentChildHandler{handlerData};
+ }
+};
+
+namespace RttiTypes {
+extern const Rtti DocumentField;
+}
+}
+#endif
diff --git a/src/core/parser/stack/DomainHandler.cpp b/src/core/parser/stack/DomainHandler.cpp
new file mode 100644
index 0000000..6571717
--- /dev/null
+++ b/src/core/parser/stack/DomainHandler.cpp
@@ -0,0 +1,276 @@
+/*
+ Ousía
+ Copyright (C) 2014, 2015 Benjamin Paaßen, Andreas Stöckel
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "DomainHandler.hpp"
+
+#include <core/common/RttiBuilder.hpp>
+#include <core/model/Domain.hpp>
+#include <core/parser/ParserScope.hpp>
+
+namespace ousia {
+
+/* DomainHandler */
+
+void DomainHandler::start(Variant::mapType &args)
+{
+ Rooted<Domain> domain = project()->createDomain(args["name"].asString());
+ domain->setLocation(location());
+
+ scope().push(domain);
+}
+
+void DomainHandler::end() { scope().pop(); }
+
+/* DomainStructHandler */
+
+void DomainStructHandler::start(Variant::mapType &args)
+{
+ scope().setFlag(ParserFlag::POST_HEAD, true);
+
+ Rooted<Domain> domain = scope().selectOrThrow<Domain>();
+
+ Rooted<StructuredClass> structuredClass = domain->createStructuredClass(
+ args["name"].asString(), args["cardinality"].asCardinality(), nullptr,
+ args["transparent"].asBool(), args["isRoot"].asBool());
+ structuredClass->setLocation(location());
+
+ const std::string &isa = args["isa"].asString();
+ if (!isa.empty()) {
+ scope().resolve<StructuredClass>(
+ isa, structuredClass, logger(),
+ [](Handle<Node> superclass, Handle<Node> structuredClass,
+ Logger &logger) {
+ if (superclass != nullptr) {
+ structuredClass.cast<StructuredClass>()->setSuperclass(
+ superclass.cast<StructuredClass>(), logger);
+ }
+ });
+ }
+
+ scope().push(structuredClass);
+}
+
+void DomainStructHandler::end() { scope().pop(); }
+
+/* DomainAnnotationHandler */
+void DomainAnnotationHandler::start(Variant::mapType &args)
+{
+ scope().setFlag(ParserFlag::POST_HEAD, true);
+
+ Rooted<Domain> domain = scope().selectOrThrow<Domain>();
+
+ Rooted<AnnotationClass> annotationClass =
+ domain->createAnnotationClass(args["name"].asString());
+ annotationClass->setLocation(location());
+
+ scope().push(annotationClass);
+}
+
+void DomainAnnotationHandler::end() { scope().pop(); }
+
+/* DomainAttributesHandler */
+
+void DomainAttributesHandler::start(Variant::mapType &args)
+{
+ // Fetch the current typesystem and create the struct node
+ Rooted<Descriptor> parent = scope().selectOrThrow<Descriptor>();
+
+ Rooted<StructType> attrDesc = parent->getAttributesDescriptor();
+ attrDesc->setLocation(location());
+
+ scope().push(attrDesc);
+}
+
+void DomainAttributesHandler::end() { scope().pop(); }
+
+/* DomainFieldHandler */
+
+void DomainFieldHandler::start(Variant::mapType &args)
+{
+ FieldDescriptor::FieldType type;
+ if (args["isSubtree"].asBool()) {
+ type = FieldDescriptor::FieldType::SUBTREE;
+ } else {
+ type = FieldDescriptor::FieldType::TREE;
+ }
+
+ Rooted<Descriptor> parent = scope().selectOrThrow<Descriptor>();
+
+ Rooted<FieldDescriptor> field = parent->createFieldDescriptor(
+ logger(), type, args["name"].asString(), args["optional"].asBool());
+ field->setLocation(location());
+
+ scope().push(field);
+}
+
+void DomainFieldHandler::end() { scope().pop(); }
+
+/* DomainFieldRefHandler */
+
+void DomainFieldRefHandler::start(Variant::mapType &args)
+{
+ Rooted<Descriptor> parent = scope().selectOrThrow<Descriptor>();
+
+ const std::string &name = args["ref"].asString();
+ scope().resolveFieldDescriptor(
+ name, parent, logger(),
+ [](Handle<Node> field, Handle<Node> parent, Logger &logger) {
+ if (field != nullptr) {
+ parent.cast<StructuredClass>()->addFieldDescriptor(
+ field.cast<FieldDescriptor>(), logger);
+ }
+ });
+}
+
+void DomainFieldRefHandler::end() {}
+
+/* DomainPrimitiveHandler */
+
+void DomainPrimitiveHandler::start(Variant::mapType &args)
+{
+ Rooted<Descriptor> parent = scope().selectOrThrow<Descriptor>();
+
+ FieldDescriptor::FieldType fieldType;
+ if (args["isSubtree"].asBool()) {
+ fieldType = FieldDescriptor::FieldType::SUBTREE;
+ } else {
+ fieldType = FieldDescriptor::FieldType::TREE;
+ }
+
+ Rooted<FieldDescriptor> field = parent->createPrimitiveFieldDescriptor(
+ new UnknownType(manager()), logger(), fieldType,
+ 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 DomainPrimitiveHandler::end() { scope().pop(); }
+
+/* DomainChildHandler */
+
+void DomainChildHandler::start(Variant::mapType &args)
+{
+ Rooted<FieldDescriptor> field = scope().selectOrThrow<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 DomainChildHandler::end() {}
+
+/* DomainParentHandler */
+
+void DomainParentHandler::start(Variant::mapType &args)
+{
+ Rooted<StructuredClass> strct = scope().selectOrThrow<StructuredClass>();
+
+ Rooted<DomainParent> parent{
+ new DomainParent(strct->getManager(), args["ref"].asString(), strct)};
+ parent->setLocation(location());
+ scope().push(parent);
+}
+
+void DomainParentHandler::end() { scope().pop(); }
+
+/* DomainParentFieldHandler */
+void DomainParentFieldHandler::start(Variant::mapType &args)
+{
+ Rooted<DomainParent> parentNameNode = scope().selectOrThrow<DomainParent>();
+ 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 =
+ parentNameNode->getParent().cast<StructuredClass>();
+
+ // resolve the parent, create the declared field and add the declared
+ // StructuredClass as child to it.
+ scope().resolve<Descriptor>(
+ parentNameNode->getName(), strct, logger(),
+ [type, name, optional](Handle<Node> parent, Handle<Node> strct,
+ Logger &logger) {
+ if (parent != nullptr) {
+ Rooted<FieldDescriptor> field =
+ parent.cast<Descriptor>()->createFieldDescriptor(
+ logger, type, name, optional);
+ field->addChild(strct.cast<StructuredClass>());
+ }
+ });
+}
+
+void DomainParentFieldHandler::end() {}
+
+/* DomainParentFieldRefHandler */
+
+void DomainParentFieldRefHandler::start(Variant::mapType &args)
+{
+ Rooted<DomainParent> parentNameNode = scope().selectOrThrow<DomainParent>();
+
+ const std::string &name = args["ref"].asString();
+ Rooted<StructuredClass> strct =
+ parentNameNode->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>(
+ parentNameNode->getName(), strct, logger(),
+ [name, loc](Handle<Node> parent, Handle<Node> strct, Logger &logger) {
+ if (parent != nullptr) {
+ Rooted<FieldDescriptor> field =
+ parent.cast<Descriptor>()->getFieldDescriptor(name);
+ if (field == nullptr) {
+ logger.error(
+ std::string("Could not find referenced field ") + name,
+ loc);
+ return;
+ }
+ field->addChild(strct.cast<StructuredClass>());
+ }
+ });
+}
+
+void DomainParentFieldRefHandler::end() {}
+
+namespace RttiTypes {
+const Rtti DomainParent =
+ RttiBuilder<ousia::DomainParent>("DomainParent").parent(&Node);
+}
+}
diff --git a/src/core/parser/stack/DomainHandler.hpp b/src/core/parser/stack/DomainHandler.hpp
new file mode 100644
index 0000000..5e8ea60
--- /dev/null
+++ b/src/core/parser/stack/DomainHandler.hpp
@@ -0,0 +1,200 @@
+/*
+ Ousía
+ Copyright (C) 2014, 2015 Benjamin Paaßen, Andreas Stöckel
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file DomainHandler.hpp
+ *
+ * @author Andreas Stöckel (astoecke@techfak.uni-bielefeld.de)
+ */
+
+#ifndef _OUSIA_DOMAIN_HANDLER_HPP_
+#define _OUSIA_DOMAIN_HANDLER_HPP_
+
+#include <core/common/Variant.hpp>
+
+#include "Handler.hpp"
+
+namespace ousia {
+
+// Forward declarations
+class Rtti;
+
+class DomainHandler : public StaticHandler {
+public:
+ using StaticHandler::StaticHandler;
+
+ bool start(Variant::mapType &args) override;
+
+ void end() override;
+
+ static Handler *create(const HandlerData &handlerData)
+ {
+ return new DomainHandler{handlerData};
+ }
+};
+
+class DomainStructHandler : public StaticHandler {
+public:
+ using StaticHandler::StaticHandler;
+
+ bool start(Variant::mapType &args) override;
+
+ void end() override;
+
+ static Handler *create(const HandlerData &handlerData)
+ {
+ return new DomainStructHandler{handlerData};
+ }
+};
+
+class DomainAnnotationHandler : public StaticHandler {
+public:
+ using StaticHandler::StaticHandler;
+
+ bool start(Variant::mapType &args) override;
+
+ void end() override;
+
+ static Handler *create(const HandlerData &handlerData)
+ {
+ return new DomainAnnotationHandler{handlerData};
+ }
+};
+
+class DomainAttributesHandler : public StaticHandler {
+public:
+ using StaticHandler::StaticHandler;
+
+ bool start(Variant::mapType &args) override;
+
+ void end() override;
+
+ static Handler *create(const HandlerData &handlerData)
+ {
+ return new DomainAttributesHandler{handlerData};
+ }
+};
+
+class DomainFieldHandler : public StaticHandler {
+public:
+ using StaticHandler::StaticHandler;
+
+ bool start(Variant::mapType &args) override;
+
+ void end() override;
+
+ static Handler *create(const HandlerData &handlerData)
+ {
+ return new DomainFieldHandler{handlerData};
+ }
+};
+
+class DomainFieldRefHandler : public StaticHandler {
+public:
+ using StaticHandler::StaticHandler;
+
+ bool start(Variant::mapType &args) override;
+
+ void end() override;
+
+ static Handler *create(const HandlerData &handlerData)
+ {
+ return new DomainFieldRefHandler{handlerData};
+ }
+};
+
+class DomainPrimitiveHandler : public StaticHandler {
+public:
+ using StaticHandler::StaticHandler;
+
+ bool start(Variant::mapType &args) override;
+
+ void end() override;
+
+ static Handler *create(const HandlerData &handlerData)
+ {
+ return new DomainPrimitiveHandler{handlerData};
+ }
+};
+
+class DomainChildHandler : public StaticHandler {
+public:
+ using StaticHandler::StaticHandler;
+
+ bool start(Variant::mapType &args) override;
+
+ void end() override;
+
+ static Handler *create(const HandlerData &handlerData)
+ {
+ return new DomainChildHandler{handlerData};
+ }
+};
+
+class DomainParent : public Node {
+public:
+ using Node::Node;
+};
+
+namespace RttiTypes {
+extern const Rtti DomainParent;
+}
+
+class DomainParentHandler : public StaticHandler {
+public:
+ using StaticHandler::StaticHandler;
+
+ bool start(Variant::mapType &args) override;
+
+ void end() override;
+
+ static Handler *create(const HandlerData &handlerData)
+ {
+ return new DomainParentHandler{handlerData};
+ }
+};
+
+class DomainParentFieldHandler : public StaticHandler {
+public:
+ using StaticHandler::StaticHandler;
+
+ bool start(Variant::mapType &args) override;
+
+ void end() override;
+
+ static Handler *create(const HandlerData &handlerData)
+ {
+ return new DomainParentFieldHandler{handlerData};
+ }
+};
+
+class DomainParentFieldRefHandler : public StaticHandler {
+public:
+ using StaticHandler::StaticHandler;
+
+ bool start(Variant::mapType &args) override;
+
+ void end() override;
+
+ static Handler *create(const HandlerData &handlerData)
+ {
+ return new DomainParentFieldRefHandler{handlerData};
+ }
+};
+}
+#endif
diff --git a/src/core/parser/stack/Handler.cpp b/src/core/parser/stack/Handler.cpp
index 54dfe3e..a608f7f 100644
--- a/src/core/parser/stack/Handler.cpp
+++ b/src/core/parser/stack/Handler.cpp
@@ -184,7 +184,7 @@ bool StaticHandler::annotationEnd(const Variant &className,
bool StaticHandler::data(const Variant &data)
{
- // No data supported
+ logger().error("Did not expect any data here", data);
return false;
}
diff --git a/src/core/parser/stack/ImportIncludeHandler.cpp b/src/core/parser/stack/ImportIncludeHandler.cpp
new file mode 100644
index 0000000..94ee82d
--- /dev/null
+++ b/src/core/parser/stack/ImportIncludeHandler.cpp
@@ -0,0 +1,96 @@
+/*
+ Ousía
+ Copyright (C) 2014, 2015 Benjamin Paaßen, Andreas Stöckel
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "ImportIncludeHandler.hpp"
+
+#include <core/parser/ParserScope.hpp>
+
+namespace ousia {
+
+/* ImportIncludeHandler */
+
+void ImportIncludeHandler::start(Variant::mapType &args)
+{
+ rel = args["rel"].asString();
+ type = args["type"].asString();
+ src = args["src"].asString();
+ srcInArgs = !src.empty();
+}
+
+void ImportIncludeHandler::data(const std::string &data, int field)
+{
+ if (srcInArgs) {
+ logger().error("\"src\" attribute has already been set");
+ return;
+ }
+ if (field != 0) {
+ logger().error("Command has only one field.");
+ return;
+ }
+ src.append(data);
+}
+
+/* ImportHandler */
+
+void ImportHandler::start(Variant::mapType &args)
+{
+ ImportIncludeHandler::start(args);
+
+ // Make sure imports are still possible
+ if (scope().getFlag(ParserFlag::POST_HEAD)) {
+ logger().error("Imports must be listed before other commands.",
+ location());
+ return;
+ }
+}
+
+void ImportHandler::end()
+{
+ // Fetch the last node and check whether an import is valid at this
+ // position
+ Rooted<Node> leaf = scope().getLeaf();
+ if (leaf == nullptr || !leaf->isa(&RttiTypes::RootNode)) {
+ logger().error(
+ "Import not supported here, must be inside a document, domain "
+ "or typesystem command.",
+ location());
+ return;
+ }
+ Rooted<RootNode> leafRootNode = leaf.cast<RootNode>();
+
+ // Perform the actual import, register the imported node within the leaf
+ // node
+ Rooted<Node> imported =
+ context().import(src, type, rel, leafRootNode->getReferenceTypes());
+ if (imported != nullptr) {
+ leafRootNode->reference(imported);
+ }
+}
+
+/* IncludeHandler */
+
+void IncludeHandler::start(Variant::mapType &args)
+{
+ ImportIncludeHandler::start(args);
+}
+
+void IncludeHandler::end()
+{
+ context().include(src, type, rel, {&RttiTypes::Node});
+}
+}
diff --git a/src/core/parser/stack/ImportIncludeHandler.hpp b/src/core/parser/stack/ImportIncludeHandler.hpp
new file mode 100644
index 0000000..f9abe55
--- /dev/null
+++ b/src/core/parser/stack/ImportIncludeHandler.hpp
@@ -0,0 +1,90 @@
+/*
+ Ousía
+ Copyright (C) 2014, 2015 Benjamin Paaßen, Andreas Stöckel
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file ImportIncludeHandler.hpp
+ *
+ * Contains the conceptually similar handlers for the "include" and "import"
+ * commands.
+ *
+ * @author Andreas Stöckel (astoecke@techfak.uni-bielefeld.de)
+ */
+
+#ifndef _OUSIA_IMPORT_INCLUDE_HANDLER_HPP_
+#define _OUSIA_IMPORT_INCLUDE_HANDLER_HPP_
+
+#include <core/common/Variant.hpp>
+#include <core/parser/ParserStack.hpp>
+
+namespace ousia {
+
+/**
+ * The ImportHandler is responsible for handling the "import" command. An import
+ * creates a reference to a specified file. The specified file is parsed (if
+ * this has not already been done) outside of the context of the current file.
+ * If the specified resource has already been parsed, a reference to the already
+ * parsed file is inserted. Imports are only possible before no other content
+ * has been parsed.
+ */
+class ImportHandler : public StaticFieldHandler {
+public:
+ using StaticFieldHandler::StaticFieldHandler;
+
+ void doHandle(const Variant &fieldData,
+ const Variant::mapType &args) override;
+
+ /**
+ * Creates a new instance of the ImportHandler.
+ *
+ * @param handlerData is the data that is passed to the constructor of the
+ * Handler base class and used there to e.g. access the ParserContext and
+ * the Callbacks instance.
+ */
+ static Handler *create(const HandlerData &handlerData)
+ {
+ return new ImportHandler{handlerData};
+ }
+};
+
+/**
+ * The IncludeHandler is responsible for handling the "include" command. The
+ * included file is parsed in the context of the current file and will change
+ * the content that is currently being parsed. Includes are possible at (almost)
+ * any position in the source file.
+ */
+class IncludeHandler : public StaticFieldHandler {
+public:
+ using StaticFieldHandler::StaticFieldHandler;
+
+ void doHandle(const Variant &fieldData,
+ const Variant::mapType &args) override;
+
+ /**
+ * Creates a new instance of the IncludeHandler.
+ *
+ * @param handlerData is the data that is passed to the constructor of the
+ * Handler base class and used there to e.g. access the ParserContext and
+ * the Callbacks instance.
+ */
+ static Handler *create(const HandlerData &handlerData)
+ {
+ return new IncludeHandler{handlerData};
+ }
+};
+}
+#endif
diff --git a/src/core/parser/stack/TypesystemHandler.cpp b/src/core/parser/stack/TypesystemHandler.cpp
new file mode 100644
index 0000000..2cc7dfb
--- /dev/null
+++ b/src/core/parser/stack/TypesystemHandler.cpp
@@ -0,0 +1,175 @@
+/*
+ Ousía
+ Copyright (C) 2014, 2015 Benjamin Paaßen, Andreas Stöckel
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "TypesystemHandler.hpp"
+
+#include <core/model/Typesystem.hpp>
+#include <core/parser/ParserScope.hpp>
+
+namespace ousia {
+
+/* TypesystemHandler */
+
+void TypesystemHandler::start(Variant::mapType &args)
+{
+ // Create the typesystem instance
+ Rooted<Typesystem> typesystem =
+ project()->createTypesystem(args["name"].asString());
+ typesystem->setLocation(location());
+
+ // Push the typesystem onto the scope, set the POST_HEAD flag to true
+ scope().push(typesystem);
+ scope().setFlag(ParserFlag::POST_HEAD, false);
+}
+
+void TypesystemHandler::end() { scope().pop(); }
+
+/* TypesystemEnumHandler */
+
+void TypesystemEnumHandler::start(Variant::mapType &args)
+{
+ scope().setFlag(ParserFlag::POST_HEAD, true);
+
+ // Fetch the current typesystem and create the enum node
+ Rooted<Typesystem> typesystem = scope().selectOrThrow<Typesystem>();
+ Rooted<EnumType> enumType =
+ typesystem->createEnumType(args["name"].asString());
+ enumType->setLocation(location());
+
+ scope().push(enumType);
+}
+
+void TypesystemEnumHandler::end() { scope().pop(); }
+
+/* TypesystemEnumEntryHandler */
+
+void TypesystemEnumEntryHandler::start(Variant::mapType &args) {}
+
+void TypesystemEnumEntryHandler::end()
+{
+ Rooted<EnumType> enumType = scope().selectOrThrow<EnumType>();
+ enumType->addEntry(entry, logger());
+}
+
+void TypesystemEnumEntryHandler::data(const std::string &data, int field)
+{
+ if (field != 0) {
+ // TODO: This should be stored in the HandlerData
+ logger().error("Enum entry only has one field.");
+ return;
+ }
+ entry.append(data);
+}
+
+/* TypesystemStructHandler */
+
+void TypesystemStructHandler::start(Variant::mapType &args)
+{
+ scope().setFlag(ParserFlag::POST_HEAD, true);
+
+ // Fetch the arguments used for creating this type
+ const std::string &name = args["name"].asString();
+ const std::string &parent = args["parent"].asString();
+
+ // Fetch the current typesystem and create the struct node
+ Rooted<Typesystem> typesystem = scope().selectOrThrow<Typesystem>();
+ Rooted<StructType> structType = typesystem->createStructType(name);
+ structType->setLocation(location());
+
+ // Try to resolve the parent type and set it as parent structure
+ if (!parent.empty()) {
+ scope().resolve<StructType>(
+ parent, structType, logger(),
+ [](Handle<Node> parent, Handle<Node> structType, Logger &logger) {
+ if (parent != nullptr) {
+ structType.cast<StructType>()->setParentStructure(
+ parent.cast<StructType>(), logger);
+ }
+ });
+ }
+ scope().push(structType);
+}
+
+void TypesystemStructHandler::end() { scope().pop(); }
+
+/* TypesystemStructFieldHandler */
+
+void TypesystemStructFieldHandler::start(Variant::mapType &args)
+{
+ // Read the argument values
+ const std::string &name = args["name"].asString();
+ const std::string &type = args["type"].asString();
+ const Variant &defaultValue = args["default"];
+ const bool optional =
+ !(defaultValue.isObject() && defaultValue.asObject() == nullptr);
+
+ Rooted<StructType> structType = scope().selectOrThrow<StructType>();
+ Rooted<Attribute> attribute =
+ structType->createAttribute(name, defaultValue, optional, logger());
+ attribute->setLocation(location());
+
+ // Try to resolve the type and default value
+ if (optional) {
+ scope().resolveTypeWithValue(
+ type, attribute, attribute->getDefaultValue(), logger(),
+ [](Handle<Node> type, Handle<Node> attribute, Logger &logger) {
+ if (type != nullptr) {
+ attribute.cast<Attribute>()->setType(type.cast<Type>(),
+ logger);
+ }
+ });
+ } else {
+ scope().resolveType(type, attribute, logger(),
+ [](Handle<Node> type, Handle<Node> attribute,
+ Logger &logger) {
+ if (type != nullptr) {
+ attribute.cast<Attribute>()->setType(type.cast<Type>(), logger);
+ }
+ });
+ }
+}
+
+void TypesystemStructFieldHandler::end() {}
+
+/* TypesystemConstantHandler */
+
+void TypesystemConstantHandler::start(Variant::mapType &args)
+{
+ scope().setFlag(ParserFlag::POST_HEAD, true);
+
+ // Read the argument values
+ const std::string &name = args["name"].asString();
+ const std::string &type = args["type"].asString();
+ const Variant &value = args["value"];
+
+ Rooted<Typesystem> typesystem = scope().selectOrThrow<Typesystem>();
+ Rooted<Constant> constant = typesystem->createConstant(name, value);
+ constant->setLocation(location());
+
+ // Try to resolve the type
+ scope().resolveTypeWithValue(
+ type, constant, constant->getValue(), logger(),
+ [](Handle<Node> type, Handle<Node> constant, Logger &logger) {
+ if (type != nullptr) {
+ constant.cast<Constant>()->setType(type.cast<Type>(), logger);
+ }
+ });
+}
+
+void TypesystemConstantHandler::end() {}
+}
diff --git a/src/core/parser/stack/TypesystemHandler.hpp b/src/core/parser/stack/TypesystemHandler.hpp
new file mode 100644
index 0000000..76a7bc9
--- /dev/null
+++ b/src/core/parser/stack/TypesystemHandler.hpp
@@ -0,0 +1,121 @@
+/*
+ Ousía
+ Copyright (C) 2014, 2015 Benjamin Paaßen, Andreas Stöckel
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file TypesystemHandler.hpp
+ *
+ * @author Andreas Stöckel (astoecke@techfak.uni-bielefeld.de)
+ */
+
+#ifndef _OUSIA_TYPESYSTEM_HANDLER_HPP_
+#define _OUSIA_TYPESYSTEM_HANDLER_HPP_
+
+#include <core/common/Variant.hpp>
+#include <core/parser/ParserStack.hpp>
+
+namespace ousia {
+
+class TypesystemHandler : public Handler {
+public:
+ using Handler::Handler;
+
+ void start(Variant::mapType &args) override;
+
+ void end() override;
+
+ static Handler *create(const HandlerData &handlerData)
+ {
+ return new TypesystemHandler{handlerData};
+ }
+};
+
+class TypesystemEnumHandler : public Handler {
+public:
+ using Handler::Handler;
+
+ void start(Variant::mapType &args) override;
+
+ void end() override;
+
+ static Handler *create(const HandlerData &handlerData)
+ {
+ return new TypesystemEnumHandler{handlerData};
+ }
+};
+
+class TypesystemEnumEntryHandler : public Handler {
+public:
+ using Handler::Handler;
+
+ std::string entry;
+
+ void start(Variant::mapType &args) override;
+
+ void end() override;
+
+ void data(const std::string &data, int field) override;
+
+ static Handler *create(const HandlerData &handlerData)
+ {
+ return new TypesystemEnumEntryHandler{handlerData};
+ }
+};
+
+class TypesystemStructHandler : public Handler {
+public:
+ using Handler::Handler;
+
+ void start(Variant::mapType &args) override;
+
+ void end() override;
+
+ static Handler *create(const HandlerData &handlerData)
+ {
+ return new TypesystemStructHandler{handlerData};
+ }
+};
+
+class TypesystemStructFieldHandler : public Handler {
+public:
+ using Handler::Handler;
+
+ void start(Variant::mapType &args) override;
+
+ void end() override;
+
+ static Handler *create(const HandlerData &handlerData)
+ {
+ return new TypesystemStructFieldHandler{handlerData};
+ }
+};
+
+class TypesystemConstantHandler : public Handler {
+public:
+ using Handler::Handler;
+
+ void start(Variant::mapType &args) override;
+
+ void end() override;
+
+ static Handler *create(const HandlerData &handlerData)
+ {
+ return new TypesystemConstantHandler{handlerData};
+ }
+};
+}
+#endif