diff options
-rw-r--r-- | CMakeLists.txt | 4 | ||||
-rw-r--r-- | src/core/parser/stack/DocumentHandler.cpp | 252 | ||||
-rw-r--r-- | src/core/parser/stack/DocumentHandler.hpp | 88 | ||||
-rw-r--r-- | src/core/parser/stack/DomainHandler.cpp | 276 | ||||
-rw-r--r-- | src/core/parser/stack/DomainHandler.hpp | 200 | ||||
-rw-r--r-- | src/core/parser/stack/Handler.cpp | 2 | ||||
-rw-r--r-- | src/core/parser/stack/ImportIncludeHandler.cpp | 96 | ||||
-rw-r--r-- | src/core/parser/stack/ImportIncludeHandler.hpp | 90 | ||||
-rw-r--r-- | src/core/parser/stack/TypesystemHandler.cpp | 175 | ||||
-rw-r--r-- | src/core/parser/stack/TypesystemHandler.hpp | 121 |
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 |