From cc281d91def921b7bbf5d3d4a0fce53afc5a317b Mon Sep 17 00:00:00 2001 From: Andreas Stöckel Date: Sun, 15 Feb 2015 00:07:58 +0100 Subject: Renamed parser/generic to parser/stack and made filenames much shorter --- src/core/parser/stack/Handler.cpp | 90 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 src/core/parser/stack/Handler.cpp (limited to 'src/core/parser/stack/Handler.cpp') diff --git a/src/core/parser/stack/Handler.cpp b/src/core/parser/stack/Handler.cpp new file mode 100644 index 0000000..66af2a4 --- /dev/null +++ b/src/core/parser/stack/Handler.cpp @@ -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 . +*/ + +#include + +#include "Callbacks.hpp" +#include "Handler.hpp" +#include "State.hpp" + +namespace ousia { +namespace parser_stack { + +/* Class HandlerData */ + +HandlerData::HandlerData(ParserContext &ctx, Callbacks &callbacks, + std::string name, const State &state, + const SourceLocation &location) + : ctx(ctx), + callbacks(callbacks), + name(std::move(name)), + state(state), + location(location) +{ +} + +/* Class Handler */ + +Handler::Handler(const HandlerData &internalData) : internalData(internalData) +{ +} + +Handler::~Handler() {} + +ParserContext &Handler::context() { return internalData.ctx; } + +const std::string &Handler::name() { return internalData.name; } + +ParserScope &Handler::scope() { return internalData.ctx.getScope(); } + +Manager &Handler::manager() { return internalData.ctx.getManager(); } + +Logger &Handler::logger() { return internalData.ctx.getLogger(); } + +const State &Handler::state() { return internalData.state; } + +SourceLocation Handler::location() { return internalData.location; } + +void Handler::setWhitespaceMode(WhitespaceMode whitespaceMode) +{ + internalData.callbacks.setWhitespaceMode(whitespaceMode); +} + +void Handler::registerToken(const std::string &token) +{ + internalData.callbacks.registerToken(token); +} + +void Handler::unregisterToken(const std::string &token) +{ + internalData.callbacks.unregisterToken(token); +} + +/* Class DefaultHandler */ + +/*void DefaultHandler::start(Variant::mapType &args) {} + +void DefaultHandler::end() {} + +Handler *DefaultHandler::create(const data &data) +{ + return new DefaultHandler{data}; +}*/ +} +} + -- cgit v1.2.3 From 343900991ee5e2558d45187fe0129a144a5e013a Mon Sep 17 00:00:00 2001 From: Andreas Stöckel Date: Sun, 15 Feb 2015 00:11:11 +0100 Subject: Implemented StaticFieldHandler and EmptyHandler default handler classes --- src/core/parser/stack/Handler.cpp | 184 +++++++++++++++++++++++++++++++++----- src/core/parser/stack/Handler.hpp | 169 +++++++++++++++++++++++++--------- 2 files changed, 288 insertions(+), 65 deletions(-) (limited to 'src/core/parser/stack/Handler.cpp') diff --git a/src/core/parser/stack/Handler.cpp b/src/core/parser/stack/Handler.cpp index 66af2a4..73084cd 100644 --- a/src/core/parser/stack/Handler.cpp +++ b/src/core/parser/stack/Handler.cpp @@ -16,6 +16,8 @@ along with this program. If not, see . */ +#include +#include #include #include "Callbacks.hpp" @@ -40,51 +42,191 @@ HandlerData::HandlerData(ParserContext &ctx, Callbacks &callbacks, /* Class Handler */ -Handler::Handler(const HandlerData &internalData) : internalData(internalData) -{ -} +Handler::Handler(const HandlerData &handlerData) : handlerData(handlerData) {} Handler::~Handler() {} -ParserContext &Handler::context() { return internalData.ctx; } - -const std::string &Handler::name() { return internalData.name; } - -ParserScope &Handler::scope() { return internalData.ctx.getScope(); } +ParserContext &Handler::context() { return handlerData.ctx; } -Manager &Handler::manager() { return internalData.ctx.getManager(); } +ParserScope &Handler::scope() { return handlerData.ctx.getScope(); } -Logger &Handler::logger() { return internalData.ctx.getLogger(); } +Manager &Handler::manager() { return handlerData.ctx.getManager(); } -const State &Handler::state() { return internalData.state; } +Logger &Handler::logger() { return handlerData.ctx.getLogger(); } -SourceLocation Handler::location() { return internalData.location; } +SourceLocation Handler::location() { return handlerData.location; } void Handler::setWhitespaceMode(WhitespaceMode whitespaceMode) { - internalData.callbacks.setWhitespaceMode(whitespaceMode); + handlerData.callbacks.setWhitespaceMode(whitespaceMode); } void Handler::registerToken(const std::string &token) { - internalData.callbacks.registerToken(token); + handlerData.callbacks.registerToken(token); } void Handler::unregisterToken(const std::string &token) { - internalData.callbacks.unregisterToken(token); + handlerData.callbacks.unregisterToken(token); +} + +const std::string &Handler::getName() const { return handlerData.name; } + +const State &Handler::getState() const { return handlerData.state; } + +/* Class EmptyHandler */ + +bool EmptyHandler::start(const Variant::mapType &args) +{ + // Just accept anything + return true; +} + +void EmptyHandler::end() +{ + // Do nothing if a command ends +} + +bool EmptyHandler::fieldStart(bool &isDefaultField, size_t fieldIndex) +{ + // Accept any field + return true; +} + +void EmptyHandler::fieldEnd() +{ + // Do not handle fields +} + +bool EmptyHandler::annotationStart(const Variant &className, + const Variant::mapType &args) +{ + // Accept any data + return true; +} + +bool EmptyHandler::annotationEnd(const Variant &className, + const Variant &elementName) +{ + // Accept any annotation + return true; +} + +bool EmptyHandler::data(const Variant &data) +{ + // Support any data + return true; +} + +/* Class StaticHandler */ + +bool StaticHandler::start(const Variant::mapType &args) +{ + // Do nothing in the default implementation, accept anything + return true; } -/* Class DefaultHandler */ +void StaticHandler::end() +{ + // Do nothing here +} -/*void DefaultHandler::start(Variant::mapType &args) {} +bool StaticHandler::fieldStart(bool &isDefault, size_t fieldIdx) +{ + // Return true if either the default field is requested or the field index + // is zero. This simulates that there is exactly one field (a default field) + if (fieldIdx == 0) { + isDefault = true; + return true; + } + return false; +} -void DefaultHandler::end() {} +void StaticHandler::fieldEnd() +{ + // Do nothing here +} + +bool StaticHandler::annotationStart(const Variant &className, + const Variant::mapType &args) +{ + // No annotations supported + return false; +} + +bool StaticHandler::annotationEnd(const Variant &className, + const Variant &elementName) +{ + // No annotations supported + return false; +} -Handler *DefaultHandler::create(const data &data) +bool StaticHandler::data(const Variant &data) { - return new DefaultHandler{data}; -}*/ + // No data supported + return false; +} + +/* Class StaticFieldHandler */ + +StaticFieldHandler::StaticFieldHandler(const HandlerData &handlerData, + const std::string &argName) + : StaticHandler(handlerData), argName(argName), handled(false) +{ +} + +bool StaticFieldHandler::start(const Variant::mapType &args) +{ + if (!argName.empty()) { + auto it = args.find(argName); + if (it != args.end()) { + handled = true; + doHandle(it->second, args); + return true; + } + } + + this->args = args; + return true; +} + +void StaticFieldHandler::end() +{ + if (!handled) { + if (!argName.empty()) { + logger().error(std::string("Required argument \"") + argName + + std::string("\" is missing."), + location()); + } else { + logger().error("Command requires data, but no data given", + location()); + } + } +} + +bool StaticFieldHandler::data(const Variant &data) +{ + // Call the doHandle function if this has not been done before + if (!handled) { + handled = true; + doHandle(data, args); + return true; + } + + // The doHandle function was already called, print an error message + logger().error( + std::string("Found data, but the corresponding argument \"") + argName + + std::string("\" was already specified"), + data); + + // Print the location at which the attribute was originally specified + auto it = args.find(argName); + if (it != args.end()) { + logger().note(std::string("Attribute was specified here:"), it->second); + } + return false; +} } } diff --git a/src/core/parser/stack/Handler.hpp b/src/core/parser/stack/Handler.hpp index 0701343..8c3d8c4 100644 --- a/src/core/parser/stack/Handler.hpp +++ b/src/core/parser/stack/Handler.hpp @@ -16,10 +16,9 @@ along with this program. If not, see . */ -#ifndef _OUSIA_PARSER_STATE_HANDLER_HPP_ -#define _OUSIA_PARSER_STATE_HANDLER_HPP_ +#ifndef _OUSIA_PARSER_STACK_HANDLER_HPP_ +#define _OUSIA_PARSER_STACK_HANDLER_HPP_ -#include #include #include @@ -29,13 +28,12 @@ namespace ousia { // Forward declarations class ParserContext; -class Callbacks; class Logger; -class Project; namespace parser_stack { // More forward declarations +class Callbacks; class State; /** @@ -96,7 +94,7 @@ private: /** * Structure containing the internal handler data. */ - const HandlerData internalData; + const HandlerData handlerData; protected: /** @@ -105,7 +103,7 @@ protected: * @param data is a structure containing all data being passed to the * handler. */ - Handler(const HandlerData &internalData); + Handler(const HandlerData &handlerData); /** * Returns a reference at the ParserContext. @@ -114,13 +112,6 @@ protected: */ ParserContext &context(); - /** - * Returns the command name for which the handler was created. - * - * @return a const reference at the command name. - */ - const std::string &name(); - /** * Returns a reference at the ParserScope instance. * @@ -143,13 +134,6 @@ protected: */ Logger &logger(); - /** - * Reference at the State descriptor for which this Handler was created. - * - * @return a const reference at the constructing State descriptor. - */ - const State &state(); - /** * Returns the current location in the source file. * @@ -192,6 +176,20 @@ public: */ void unregisterToken(const std::string &token); + /** + * Returns the command name for which the handler was created. + * + * @return a const reference at the command name. + */ + const std::string &getName() const; + + /** + * Reference at the State descriptor for which this Handler was created. + * + * @return a const reference at the constructing State descriptor. + */ + const State &getState() const; + /** * Called when the command that was specified in the constructor is * instanciated. @@ -200,7 +198,7 @@ public: * @return true if the handler was successful in starting the element it * represents, false otherwise. */ - virtual bool start(Variant::mapType &args) = 0; + virtual bool start(const Variant::mapType &args) = 0; /** * Called before the command for which this handler is defined ends (is @@ -216,16 +214,12 @@ public: * even though the corresponding structure does not have a field, as long as * no data is fed into the field). * - * @param isDefaultField is set to true if the field that is being started - * is the default/tree field. The handler should set the value of this - * variable to true if the referenced field is indeed the default field. - * @param isImplicit is set to true if the field is implicitly being started - * by the stack (this field always implies isDefaultField being set to - * true). - * @param fieldIndex is the numerical index of the field. + * @param isDefault is set to true if the field that is being started is the + * default/tree field. The handler should set the value of this variable to + * true if the referenced field is indeed the default field. + * @param fieldIdx is the numerical index of the field. */ - virtual bool fieldStart(bool &isDefaultField, bool isImplicit, - size_t fieldIndex) = 0; + virtual bool fieldStart(bool &isDefault, size_t fieldIdx) = 0; /** * Called when a previously opened field ends, while the handler is active. @@ -244,10 +238,11 @@ public: * @return true if the mentioned annotation could be started here, false * if an error occurred. */ - virtual bool annotationStart(Variant className, Variant::mapType &args) = 0; + virtual bool annotationStart(const Variant &className, + const Variant::mapType &args) = 0; /** - * Called whenever an annotation ends while this handler is active. The + * Called whenever an annotation ends while this handler is active. The * function should return true if ending the annotation was successful, * false otherwise. * @@ -258,16 +253,19 @@ public: * @return true if the mentioned annotation could be started here, false if * an error occurred. */ - virtual bool annotationEnd(Variant className, Variant elementName) = 0; + virtual bool annotationEnd(const Variant &className, + const Variant &elementName) = 0; /** * Called whenever raw data (int the form of a string) is available for the - * Handler instance. + * Handler instance. Should return true if the data could be handled, false + * otherwise. * * @param data is a string variant containing the character data and its * location. + * @return true if the data could be handled, false otherwise. */ - virtual void data(Variant data) = 0; + virtual bool data(const Variant &data) = 0; }; /** @@ -281,22 +279,105 @@ public: using HandlerConstructor = Handler *(*)(const HandlerData &handlerData); /** - * The DefaultHandler class is used in case no element handler is specified in - * the State descriptor. + * The EmptyHandler class is used in case no element handler is specified in + * the State descriptor. It just accepts all data and does nothing. */ -/*class EmptyHandler : public Handler { -public: +class EmptyHandler : public Handler { +protected: using Handler::Handler; - void start(Variant::mapType &args) override; - +public: + bool start(const Variant::mapType &args) override; void end() override; + bool fieldStart(bool &isDefault, size_t fieldIdx) override; + void fieldEnd() override; + bool annotationStart(const Variant &className, + const Variant::mapType &args) override; + bool annotationEnd(const Variant &className, + const Variant &elementName) override; + bool data(const Variant &data) override; + /** + * Creates an instance of the EmptyHandler class. + */ static Handler *create(const HandlerData &handlerData); -};*/ +}; +/** + * The StaticHandler class is used to handle predifined commands which do + * neither support annotations, nor multiple fields. Child classes can decide + * whether a single data field should be used. + */ +class StaticHandler : public Handler { +protected: + using Handler::Handler; + +public: + bool start(const Variant::mapType &args) override; + void end() override; + bool fieldStart(bool &isDefault, size_t fieldIdx) override; + void fieldEnd() override; + bool annotationStart(const Variant &className, + const Variant::mapType &args) override; + bool annotationEnd(const Variant &className, + const Variant &elementName) override; + bool data(const Variant &data) override; +}; + +/** + * The StaticFieldHandler class is used to handle predifined commands which do + * neither support annotations, nor multiple fields. Additionally, it captures a + * data entry from a single default field. + */ +class StaticFieldHandler : public StaticHandler { +private: + /** + * Set to the name of the data argument that should be used instead of the + * data field, if no data field is given. + */ + std::string argName; + + /** + * Set to true, once the "doHandle" function has been called. + */ + bool handled; + + /** + * Map containing the arguments given in the start function. + */ + Variant::mapType args; + +protected: + /** + * Constructor of the StaticFieldHandler class. + * + * @param handlerData is a structure containing the internal data that + * should be stored inside the handler. + * @param name of the data argument that -- if present -- should be used + * instead of the data field. If empty, data is not captured from the + * arguments. If both, data in the data field and the argument, are given, + * this results in an error. + */ + StaticFieldHandler(const HandlerData &handlerData, + const std::string &argName); + + /** + * Function that should be overriden in order to handle the field data and + * the other arguments. This function is not called if no data was given. + * + * @param fieldData is the captured field data. + * @param args are the arguments that were given in the "start" function. + */ + virtual void doHandle(const Variant &fieldData, + const Variant::mapType &args) = 0; + +public: + bool start(const Variant::mapType &args) override; + void end() override; + bool data(const Variant &data) override; +}; } } -#endif /* _OUSIA_PARSER_STATE_HANDLER_HPP_ */ +#endif /* _OUSIA_PARSER_STACK_HANDLER_HPP_ */ -- cgit v1.2.3 From 22c9d5b5504c81902ccbfae386cf69351d7d0209 Mon Sep 17 00:00:00 2001 From: Andreas Stöckel Date: Sun, 15 Feb 2015 00:14:12 +0100 Subject: Commented out Callbacks in Handler, this is not implemented yet --- src/core/parser/stack/Handler.cpp | 40 ++++++++++++++++++++++++++++---------- src/core/parser/stack/Handler.hpp | 41 ++++++++++++++++++++++++++++++++++----- 2 files changed, 66 insertions(+), 15 deletions(-) (limited to 'src/core/parser/stack/Handler.cpp') diff --git a/src/core/parser/stack/Handler.cpp b/src/core/parser/stack/Handler.cpp index 73084cd..54dfe3e 100644 --- a/src/core/parser/stack/Handler.cpp +++ b/src/core/parser/stack/Handler.cpp @@ -29,12 +29,12 @@ namespace parser_stack { /* Class HandlerData */ -HandlerData::HandlerData(ParserContext &ctx, Callbacks &callbacks, - std::string name, const State &state, +HandlerData::HandlerData(ParserContext &ctx, /*Callbacks &callbacks,*/ + const std::string &name, const State &state, const SourceLocation &location) : ctx(ctx), - callbacks(callbacks), - name(std::move(name)), + /*callbacks(callbacks),*/ + name(name), state(state), location(location) { @@ -42,7 +42,10 @@ HandlerData::HandlerData(ParserContext &ctx, Callbacks &callbacks, /* Class Handler */ -Handler::Handler(const HandlerData &handlerData) : handlerData(handlerData) {} +Handler::Handler(const HandlerData &handlerData) + : handlerData(handlerData), internalLogger(nullptr) +{ +} Handler::~Handler() {} @@ -52,29 +55,41 @@ ParserScope &Handler::scope() { return handlerData.ctx.getScope(); } Manager &Handler::manager() { return handlerData.ctx.getManager(); } -Logger &Handler::logger() { return handlerData.ctx.getLogger(); } +Logger &Handler::logger() +{ + if (internalLogger != nullptr) { + return *internalLogger; + } + return handlerData.ctx.getLogger(); +} -SourceLocation Handler::location() { return handlerData.location; } +const SourceLocation &Handler::location() const { return handlerData.location; } void Handler::setWhitespaceMode(WhitespaceMode whitespaceMode) { - handlerData.callbacks.setWhitespaceMode(whitespaceMode); + /*handlerData.callbacks.setWhitespaceMode(whitespaceMode);*/ } void Handler::registerToken(const std::string &token) { - handlerData.callbacks.registerToken(token); + /*handlerData.callbacks.registerToken(token);*/ } void Handler::unregisterToken(const std::string &token) { - handlerData.callbacks.unregisterToken(token); + /*handlerData.callbacks.unregisterToken(token);*/ } const std::string &Handler::getName() const { return handlerData.name; } const State &Handler::getState() const { return handlerData.state; } +void Handler::setLogger(Logger &logger) { internalLogger = &logger; } + +void Handler::resetLogger() { internalLogger = nullptr; } + +const SourceLocation &Handler::getLocation() const { return location(); } + /* Class EmptyHandler */ bool EmptyHandler::start(const Variant::mapType &args) @@ -119,6 +134,11 @@ bool EmptyHandler::data(const Variant &data) return true; } +Handler *EmptyHandler::create(const HandlerData &handlerData) +{ + return new EmptyHandler(handlerData); +} + /* Class StaticHandler */ bool StaticHandler::start(const Variant::mapType &args) diff --git a/src/core/parser/stack/Handler.hpp b/src/core/parser/stack/Handler.hpp index 8c3d8c4..eeaf555 100644 --- a/src/core/parser/stack/Handler.hpp +++ b/src/core/parser/stack/Handler.hpp @@ -23,10 +23,12 @@ #include #include +#include namespace ousia { // Forward declarations +class ParserScope; class ParserContext; class Logger; @@ -53,7 +55,7 @@ public: * modifying the behaviour of the parser (like registering tokens, setting * the data type or changing the whitespace handling mode). */ - Callbacks &callbacks; + // Callbacks &callbacks; /** * Contains the name of the command that is being handled. @@ -80,7 +82,8 @@ public: * @param state is the state this handler was called for. * @param location is the location at which the handler is created. */ - HandlerData(ParserContext &ctx, Callbacks &callbacks, std::string name, + HandlerData(ParserContext &ctx, + /*Callbacks &callbacks,*/ const std::string &name, const State &state, const SourceLocation &location); }; @@ -96,6 +99,12 @@ private: */ const HandlerData handlerData; + /** + * Reference at the current logger. If not nullptr, this will override the + * logger from the ParserContext specified in the handlerData. + */ + Logger *internalLogger; + protected: /** * Constructor of the Handler class. @@ -135,11 +144,12 @@ protected: Logger &logger(); /** - * Returns the current location in the source file. + * Returns the location of the element in the source file, for which this + * Handler was created. * - * @return the current location in the source file. + * @return the location of the Handler in the source file. */ - SourceLocation location(); + const SourceLocation &location() const; public: /** @@ -190,6 +200,27 @@ public: */ const State &getState() const; + /** + * Sets the internal logger to the given logger instance. + * + * @param logger is the Logger instance to which the logger should be set. + */ + void setLogger(Logger &logger); + + /** + * Resets the logger instance to the logger instance provided in the + * ParserContext. + */ + void resetLogger(); + + /** + * Returns the location of the element in the source file, for which this + * Handler was created. + * + * @return the location of the Handler in the source file. + */ + const SourceLocation &getLocation() const; + /** * Called when the command that was specified in the constructor is * instanciated. -- cgit v1.2.3 From 551b7be64f207845cb05b8ec593f9bf2d7f0c940 Mon Sep 17 00:00:00 2001 From: Andreas Stöckel Date: Sat, 14 Feb 2015 23:25:38 +0100 Subject: Included handler classes from master --- CMakeLists.txt | 4 + src/core/parser/stack/DocumentHandler.cpp | 252 ++++++++++++++++++++++ src/core/parser/stack/DocumentHandler.hpp | 88 ++++++++ src/core/parser/stack/DomainHandler.cpp | 276 +++++++++++++++++++++++++ src/core/parser/stack/DomainHandler.hpp | 200 ++++++++++++++++++ src/core/parser/stack/Handler.cpp | 2 +- src/core/parser/stack/ImportIncludeHandler.cpp | 96 +++++++++ src/core/parser/stack/ImportIncludeHandler.hpp | 90 ++++++++ src/core/parser/stack/TypesystemHandler.cpp | 175 ++++++++++++++++ src/core/parser/stack/TypesystemHandler.hpp | 121 +++++++++++ 10 files changed, 1303 insertions(+), 1 deletion(-) create mode 100644 src/core/parser/stack/DocumentHandler.cpp create mode 100644 src/core/parser/stack/DocumentHandler.hpp create mode 100644 src/core/parser/stack/DomainHandler.cpp create mode 100644 src/core/parser/stack/DomainHandler.hpp create mode 100644 src/core/parser/stack/ImportIncludeHandler.cpp create mode 100644 src/core/parser/stack/ImportIncludeHandler.hpp create mode 100644 src/core/parser/stack/TypesystemHandler.cpp create mode 100644 src/core/parser/stack/TypesystemHandler.hpp (limited to 'src/core/parser/stack/Handler.cpp') 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 . +*/ + +#include "DocumentHandler.hpp" + +#include + +#include +#include +#include +#include +#include +#include + +namespace ousia { + +/* DocumentHandler */ + +void DocumentHandler::start(Variant::mapType &args) +{ + Rooted 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 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( + parentNode.cast().get()); + } else if (parentNode->isa(&RttiTypes::AnnotationEntity)) { + parent = static_cast( + parentNode.cast().get()); + } +} + +void DocumentChildHandler::createPath(const NodeVector &path, + DocumentEntity *&parent) +{ + size_t S = path.size(); + for (size_t p = 1; p < S; p = p + 2) { + parent = static_cast( + parent->createChildStructuredEntity( + path[p].cast(), Variant::mapType{}, + path[p - 1]->getName(), "").get()); + } +} + +void DocumentChildHandler::start(Variant::mapType &args) +{ + scope().setFlag(ParserFlag::POST_HEAD, true); + Rooted 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 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 strct = + scope().resolve(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 entity; + if (parentNode->isa(&RttiTypes::Document)) { + entity = parentNode.cast()->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 DocumentChildHandler::convertData( + Handle 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 parentNode = scope().selectOrThrow( + {&RttiTypes::StructuredEntity, &RttiTypes::AnnotationEntity, + &RttiTypes::DocumentField}); + + std::string fieldName; + DocumentEntity *parent; + bool inField; + + preamble(parentNode, fieldName, parent, inField); + + Rooted desc = parent->getDescriptor(); + /* + * We distinguish two cases here: One for fields that are given. + */ + if (fieldName != DEFAULT_FIELD_NAME) { + // retrieve the actual FieldDescriptor + Rooted 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 fields = desc->getDefaultFields(); + std::vector 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 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("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 . +*/ + +/** + * @file DocumentHandler.hpp + * + * @author Andreas Stöckel (astoecke@techfak.uni-bielefeld.de) + */ + +#ifndef _OUSIA_DOCUMENT_HANDLER_HPP_ +#define _OUSIA_DOCUMENT_HANDLER_HPP_ + +#include + +#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 parentNode, std::string &fieldName, + DocumentEntity *&parent, bool &inField); + + void createPath(const NodeVector &path, DocumentEntity *&parent); + + std::pair convertData(Handle 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 . +*/ + +#include "DomainHandler.hpp" + +#include +#include +#include + +namespace ousia { + +/* DomainHandler */ + +void DomainHandler::start(Variant::mapType &args) +{ + Rooted 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 = scope().selectOrThrow(); + + Rooted 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( + isa, structuredClass, logger(), + [](Handle superclass, Handle structuredClass, + Logger &logger) { + if (superclass != nullptr) { + structuredClass.cast()->setSuperclass( + superclass.cast(), logger); + } + }); + } + + scope().push(structuredClass); +} + +void DomainStructHandler::end() { scope().pop(); } + +/* DomainAnnotationHandler */ +void DomainAnnotationHandler::start(Variant::mapType &args) +{ + scope().setFlag(ParserFlag::POST_HEAD, true); + + Rooted domain = scope().selectOrThrow(); + + Rooted 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 parent = scope().selectOrThrow(); + + Rooted 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 parent = scope().selectOrThrow(); + + Rooted 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 parent = scope().selectOrThrow(); + + const std::string &name = args["ref"].asString(); + scope().resolveFieldDescriptor( + name, parent, logger(), + [](Handle field, Handle parent, Logger &logger) { + if (field != nullptr) { + parent.cast()->addFieldDescriptor( + field.cast(), logger); + } + }); +} + +void DomainFieldRefHandler::end() {} + +/* DomainPrimitiveHandler */ + +void DomainPrimitiveHandler::start(Variant::mapType &args) +{ + Rooted parent = scope().selectOrThrow(); + + FieldDescriptor::FieldType fieldType; + if (args["isSubtree"].asBool()) { + fieldType = FieldDescriptor::FieldType::SUBTREE; + } else { + fieldType = FieldDescriptor::FieldType::TREE; + } + + Rooted 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, field, logger(), + [](Handle type, Handle field, + Logger &logger) { + if (type != nullptr) { + field.cast()->setPrimitiveType(type.cast()); + } + }); + + scope().push(field); +} + +void DomainPrimitiveHandler::end() { scope().pop(); } + +/* DomainChildHandler */ + +void DomainChildHandler::start(Variant::mapType &args) +{ + Rooted field = scope().selectOrThrow(); + + const std::string &ref = args["ref"].asString(); + scope().resolve( + ref, field, logger(), + [](Handle child, Handle field, Logger &logger) { + if (child != nullptr) { + field.cast()->addChild( + child.cast()); + } + }); +} + +void DomainChildHandler::end() {} + +/* DomainParentHandler */ + +void DomainParentHandler::start(Variant::mapType &args) +{ + Rooted strct = scope().selectOrThrow(); + + Rooted 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 parentNameNode = scope().selectOrThrow(); + 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 strct = + parentNameNode->getParent().cast(); + + // resolve the parent, create the declared field and add the declared + // StructuredClass as child to it. + scope().resolve( + parentNameNode->getName(), strct, logger(), + [type, name, optional](Handle parent, Handle strct, + Logger &logger) { + if (parent != nullptr) { + Rooted field = + parent.cast()->createFieldDescriptor( + logger, type, name, optional); + field->addChild(strct.cast()); + } + }); +} + +void DomainParentFieldHandler::end() {} + +/* DomainParentFieldRefHandler */ + +void DomainParentFieldRefHandler::start(Variant::mapType &args) +{ + Rooted parentNameNode = scope().selectOrThrow(); + + const std::string &name = args["ref"].asString(); + Rooted strct = + parentNameNode->getParent().cast(); + auto loc = location(); + + // resolve the parent, get the referenced field and add the declared + // StructuredClass as child to it. + scope().resolve( + parentNameNode->getName(), strct, logger(), + [name, loc](Handle parent, Handle strct, Logger &logger) { + if (parent != nullptr) { + Rooted field = + parent.cast()->getFieldDescriptor(name); + if (field == nullptr) { + logger.error( + std::string("Could not find referenced field ") + name, + loc); + return; + } + field->addChild(strct.cast()); + } + }); +} + +void DomainParentFieldRefHandler::end() {} + +namespace RttiTypes { +const Rtti DomainParent = + RttiBuilder("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 . +*/ + +/** + * @file DomainHandler.hpp + * + * @author Andreas Stöckel (astoecke@techfak.uni-bielefeld.de) + */ + +#ifndef _OUSIA_DOMAIN_HANDLER_HPP_ +#define _OUSIA_DOMAIN_HANDLER_HPP_ + +#include + +#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 . +*/ + +#include "ImportIncludeHandler.hpp" + +#include + +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 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 leafRootNode = leaf.cast(); + + // Perform the actual import, register the imported node within the leaf + // node + Rooted 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 . +*/ + +/** + * @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 +#include + +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 . +*/ + +#include "TypesystemHandler.hpp" + +#include +#include + +namespace ousia { + +/* TypesystemHandler */ + +void TypesystemHandler::start(Variant::mapType &args) +{ + // Create the typesystem instance + Rooted 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 = scope().selectOrThrow(); + Rooted 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 = scope().selectOrThrow(); + 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 = scope().selectOrThrow(); + Rooted structType = typesystem->createStructType(name); + structType->setLocation(location()); + + // Try to resolve the parent type and set it as parent structure + if (!parent.empty()) { + scope().resolve( + parent, structType, logger(), + [](Handle parent, Handle structType, Logger &logger) { + if (parent != nullptr) { + structType.cast()->setParentStructure( + parent.cast(), 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 = scope().selectOrThrow(); + Rooted 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 type, Handle attribute, Logger &logger) { + if (type != nullptr) { + attribute.cast()->setType(type.cast(), + logger); + } + }); + } else { + scope().resolveType(type, attribute, logger(), + [](Handle type, Handle attribute, + Logger &logger) { + if (type != nullptr) { + attribute.cast()->setType(type.cast(), 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 = scope().selectOrThrow(); + Rooted constant = typesystem->createConstant(name, value); + constant->setLocation(location()); + + // Try to resolve the type + scope().resolveTypeWithValue( + type, constant, constant->getValue(), logger(), + [](Handle type, Handle constant, Logger &logger) { + if (type != nullptr) { + constant.cast()->setType(type.cast(), 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 . +*/ + +/** + * @file TypesystemHandler.hpp + * + * @author Andreas Stöckel (astoecke@techfak.uni-bielefeld.de) + */ + +#ifndef _OUSIA_TYPESYSTEM_HANDLER_HPP_ +#define _OUSIA_TYPESYSTEM_HANDLER_HPP_ + +#include +#include + +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 -- cgit v1.2.3 From 69ebaddbeaea1aa651a0f0babbf9283240d9c07b Mon Sep 17 00:00:00 2001 From: Andreas Stöckel Date: Sun, 15 Feb 2015 14:58:46 +0100 Subject: Slightly adapted Handler instances to new Handler, once again passing non-const references to data and start, using "parseGenericString" in DocumentHandler for resolving non-string values, added unit test for testing whether "end()" is not called if "start()" fails. --- src/core/parser/stack/DocumentHandler.cpp | 141 +++++++++++++++---------- src/core/parser/stack/DocumentHandler.hpp | 96 ++++++++++++++--- src/core/parser/stack/DomainHandler.cpp | 51 +++++---- src/core/parser/stack/DomainHandler.hpp | 28 +++-- src/core/parser/stack/Handler.cpp | 20 ++-- src/core/parser/stack/Handler.hpp | 31 +++--- src/core/parser/stack/ImportIncludeHandler.cpp | 54 ++-------- src/core/parser/stack/ImportIncludeHandler.hpp | 13 ++- src/core/parser/stack/Stack.cpp | 18 ++-- src/core/parser/stack/TypesystemHandler.cpp | 48 ++++----- src/core/parser/stack/TypesystemHandler.hpp | 131 +++++++++++++++++------ test/core/parser/stack/StackTest.cpp | 41 +++++-- 12 files changed, 422 insertions(+), 250 deletions(-) (limited to 'src/core/parser/stack/Handler.cpp') diff --git a/src/core/parser/stack/DocumentHandler.cpp b/src/core/parser/stack/DocumentHandler.cpp index ba7430d..b28f0fb 100644 --- a/src/core/parser/stack/DocumentHandler.cpp +++ b/src/core/parser/stack/DocumentHandler.cpp @@ -22,22 +22,28 @@ #include #include +#include #include #include +#include #include #include +#include namespace ousia { +namespace parser_stack { /* DocumentHandler */ -void DocumentHandler::start(Variant::mapType &args) +bool DocumentHandler::start(Variant::mapType &args) { Rooted document = - project()->createDocument(args["name"].asString()); + context().getProject()->createDocument(args["name"].asString()); document->setLocation(location()); scope().push(document); scope().setFlag(ParserFlag::POST_HEAD, false); + + return true; } void DocumentHandler::end() { scope().pop(); } @@ -48,7 +54,7 @@ void DocumentChildHandler::preamble(Handle parentNode, std::string &fieldName, DocumentEntity *&parent, bool &inField) { - // check if the parent in the structure tree was an explicit field + // Check if the parent in the structure tree was an explicit field // reference. inField = parentNode->isa(&RttiTypes::DocumentField); if (inField) { @@ -56,10 +62,11 @@ void DocumentChildHandler::preamble(Handle parentNode, parentNode = scope().selectOrThrow( {&RttiTypes::StructuredEntity, &RttiTypes::AnnotationEntity}); } else { - // if it wasn't an explicit reference, we use the default field. + // If it wasn't an explicit reference, we use the default field. fieldName = DEFAULT_FIELD_NAME; } - // reference the parent entity explicitly. + + // Reference the parent entity explicitly. parent = nullptr; if (parentNode->isa(&RttiTypes::StructuredEntity)) { parent = static_cast( @@ -73,6 +80,8 @@ void DocumentChildHandler::preamble(Handle parentNode, void DocumentChildHandler::createPath(const NodeVector &path, DocumentEntity *&parent) { + // TODO (@benjamin): These should be pushed onto the scope and poped once + // the scope is left. Otherwise stuff may not be correclty resolved. size_t S = path.size(); for (size_t p = 1; p < S; p = p + 2) { parent = static_cast( @@ -82,7 +91,7 @@ void DocumentChildHandler::createPath(const NodeVector &path, } } -void DocumentChildHandler::start(Variant::mapType &args) +bool DocumentChildHandler::start(Variant::mapType &args) { scope().setFlag(ParserFlag::POST_HEAD, true); Rooted parentNode = scope().selectOrThrow( @@ -95,7 +104,7 @@ void DocumentChildHandler::start(Variant::mapType &args) preamble(parentNode, fieldName, parent, inField); - // try to find a FieldDescriptor for the given tag if we are not in a + // 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 && @@ -104,7 +113,7 @@ void DocumentChildHandler::start(Variant::mapType &args) new DocumentField(parentNode->getManager(), fieldName, parentNode)}; field->setLocation(location()); scope().push(field); - return; + return true; } // Otherwise create a new StructuredEntity @@ -147,27 +156,39 @@ void DocumentChildHandler::start(Variant::mapType &args) } entity->setLocation(location()); scope().push(entity); + return true; } void DocumentChildHandler::end() { scope().pop(); } -std::pair DocumentChildHandler::convertData( - Handle field, Logger &logger, const std::string &data) +bool DocumentChildHandler::convertData(Handle field, + Variant &data, Logger &logger) { - // 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)); + bool valid = true; + Rooted type = field->getPrimitiveType(); + + // If the content is supposed to be of type string, we only need to check + // for "magic" values -- otherwise just call the "parseGenericString" + // function on the string data + if (type->isa(&RttiTypes::StringType)) { + const std::string &str = data.asString(); + // TODO: Referencing constants with "." separator should also work + if (Utils::isIdentifier(str)) { + data.markAsMagic(); + } + } else { + // Parse the string as generic string, assign the result + auto res = VariantReader::parseGenericString( + data.asString(), logger, data.getLocation().getSourceId(), + data.getLocation().getStart()); + data = res.second; } - // then try to parse the content using the type specification. - auto res = field->getPrimitiveType()->read( - data, logger, location().getSourceId(), location().getStart()); - return res; + // Now try to resolve the value for the primitive type + return valid && scope().resolveValue(data, type, logger); } -void DocumentChildHandler::data(const std::string &data, int fieldIdx) +bool DocumentChildHandler::data(Variant &data) { Rooted parentNode = scope().selectOrThrow( {&RttiTypes::StructuredEntity, &RttiTypes::AnnotationEntity, @@ -180,11 +201,10 @@ void DocumentChildHandler::data(const std::string &data, int fieldIdx) preamble(parentNode, fieldName, parent, inField); Rooted desc = parent->getDescriptor(); - /* - * We distinguish two cases here: One for fields that are given. - */ + + // We distinguish two cases here: One for fields that are given. if (fieldName != DEFAULT_FIELD_NAME) { - // retrieve the actual FieldDescriptor + // Retrieve the actual FieldDescriptor Rooted field = desc->getFieldDescriptor(fieldName); if (field == nullptr) { logger().error( @@ -192,49 +212,57 @@ void DocumentChildHandler::data(const std::string &data, int fieldIdx) fieldName + "\" exists in descriptor\"" + desc->getName() + "\".", location()); - return; + return false; } - // if it is not primitive at all, we can't parse the content. + // 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; + return false; } - // 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); + + // Try to convert the data variable to the correct format, abort if this + // does not work + if (!convertData(field, data, logger())) { + return false; } + + // Add it as primitive content + parent->createChildDocumentPrimitive(data, fieldName); + return true; } 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. + // 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. NodeVector fields = desc->getDefaultFields(); std::vector forks; for (auto field : fields) { - // then try to parse the content using the type specification. + // 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 path = pathRes.first; - createPath(path, parent); - // then create the primitive element. - parent->createChildDocumentPrimitive(res.second, fieldName); - return; + + // Try to convert the data variable to the correct format, abort if + // this does not work + if (!convertData(field, data, forks.back())) { + return false; } + + // Show possible warnings that were emitted by this type conversion + forks.back().commit(); + + // If that worked, construct the necessary path + auto pathRes = desc->pathTo(field, logger()); + assert(pathRes.second); + NodeVector path = pathRes.first; + createPath(path, parent); + + // Then create the primitive element + parent->createChildDocumentPrimitive(data, fieldName); + return true; } logger().error("Could not read data with any of the possible fields:"); for (size_t f = 0; f < fields.size(); f++) { @@ -242,11 +270,14 @@ void DocumentChildHandler::data(const std::string &data, int fieldIdx) SourceLocation{}, MessageMode::NO_CONTEXT); forks[f].commit(); } + return false; } + return true; +} } namespace RttiTypes { -const Rtti DocumentField = - RttiBuilder("DocumentField").parent(&Node); +const Rtti DocumentField = RttiBuilder( + "DocumentField").parent(&Node); } } diff --git a/src/core/parser/stack/DocumentHandler.hpp b/src/core/parser/stack/DocumentHandler.hpp index 475fe69..7dc4c86 100644 --- a/src/core/parser/stack/DocumentHandler.hpp +++ b/src/core/parser/stack/DocumentHandler.hpp @@ -19,13 +19,19 @@ /** * @file DocumentHandler.hpp * - * @author Andreas Stöckel (astoecke@techfak.uni-bielefeld.de) + * Contains the Handler instances used for parsing actual documents. This file + * declares to classes: The Document handler which parses the "document" command + * that introduces a new document and the "DocumentChildHandler" which parses + * the actual user defined tags. + * + * @author Benjamin Paaßen (bpaassen@techfak.uni-bielefeld.de) */ -#ifndef _OUSIA_DOCUMENT_HANDLER_HPP_ -#define _OUSIA_DOCUMENT_HANDLER_HPP_ +#ifndef _OUSIA_PARSER_STACK_DOCUMENT_HANDLER_HPP_ +#define _OUSIA_PARSER_STACK_DOCUMENT_HANDLER_HPP_ #include +#include #include "Handler.hpp" @@ -36,53 +42,117 @@ class Rtti; class DocumentEntity; class FieldDescriptor; +namespace parser_stack { +/** + * The DocumentHandler class parses the "document" tag that is used to introduce + * a new document. Note that this tag is not mandatory in osml files -- if the + * first command is not a typesystem, domain or any other declarative command, + * the DocumentHandler will be implicitly called. + */ class DocumentHandler : public StaticHandler { public: using StaticHandler::StaticHandler; bool start(Variant::mapType &args) override; - void end() 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 DocumentHandler{handlerData}; } }; +/** + * Temporary Node that is being pushed onto the ParserScope in order to indicate + * the field the parser is currently in. The name of the Node is stored in the + * "name" field of the parent Node class. + */ class DocumentField : public Node { public: using Node::Node; }; +/** + * The DocumentChildHandler class performs the actual parsing of the user + * defined elements in an Ousía document. + */ class DocumentChildHandler : public StaticHandler { private: + /** + * Code shared by both the start() and the end() method. Checks whether the + * parser currently is in a field and returns the name of this field. + * + * @param parentNode is the next possible parent node (a document, + * a structured entity, an annotation entity or a field). + * @param fieldName is an output parameter to which the name of the current + * field is written (or unchanged if we're not in a field). + * @param parent is an output parameter to which the parent document entity + * will be written. + * @param inField is set to true if we actually are in a field. + */ void preamble(Handle parentNode, std::string &fieldName, DocumentEntity *&parent, bool &inField); + /** + * Constructs all structured entites along the given path and inserts them + * into the document graph. + * + * @param path is a path containing an alternating series of structured + * classes and fields. + * @pram parent is the root entity from which the process should be started. + */ void createPath(const NodeVector &path, DocumentEntity *&parent); - std::pair convertData(Handle field, - Logger &logger, - const std::string &data); + /** + * Tries to convert the given data to the type that is specified in the + * given primitive field. + * + * @param field is the primitive field for which the data is intended. + * @param data is the is the data that should be converted, the result is + * written into this argument as output variable. + * @param logger is the Logger instance to which error messages should be + * written. Needed to allow the convertData function to write to a forked + * Logger instance. + * @return true if the operation was successful, false otherwise. + */ + bool convertData(Handle field, Variant &data, + Logger &logger); public: - using Handler::Handler; + using StaticHandler::StaticHandler; bool start(Variant::mapType &args) override; - void end() override; - - bool data(const Variant &data) override; - + bool data(Variant &data) override; + + /** + * Creates a new instance of the DocumentChildHandler. + * + * @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 DocumentChildHandler{handlerData}; } }; +} namespace RttiTypes { +/** + * RttiType for the internally used DocumentField class. + */ extern const Rtti DocumentField; } } -#endif + +#endif /* _OUSIA_PARSER_STACK_DOCUMENT_HANDLER_HPP_ */ + diff --git a/src/core/parser/stack/DomainHandler.cpp b/src/core/parser/stack/DomainHandler.cpp index 6571717..cb12543 100644 --- a/src/core/parser/stack/DomainHandler.cpp +++ b/src/core/parser/stack/DomainHandler.cpp @@ -20,25 +20,30 @@ #include #include +#include #include +#include namespace ousia { +namespace parser_stack { /* DomainHandler */ -void DomainHandler::start(Variant::mapType &args) +bool DomainHandler::start(Variant::mapType &args) { - Rooted domain = project()->createDomain(args["name"].asString()); + Rooted domain = + context().getProject()->createDomain(args["name"].asString()); domain->setLocation(location()); scope().push(domain); + return true; } void DomainHandler::end() { scope().pop(); } /* DomainStructHandler */ -void DomainStructHandler::start(Variant::mapType &args) +bool DomainStructHandler::start(Variant::mapType &args) { scope().setFlag(ParserFlag::POST_HEAD, true); @@ -63,12 +68,13 @@ void DomainStructHandler::start(Variant::mapType &args) } scope().push(structuredClass); + return true; } void DomainStructHandler::end() { scope().pop(); } /* DomainAnnotationHandler */ -void DomainAnnotationHandler::start(Variant::mapType &args) +bool DomainAnnotationHandler::start(Variant::mapType &args) { scope().setFlag(ParserFlag::POST_HEAD, true); @@ -79,13 +85,14 @@ void DomainAnnotationHandler::start(Variant::mapType &args) annotationClass->setLocation(location()); scope().push(annotationClass); + return true; } void DomainAnnotationHandler::end() { scope().pop(); } /* DomainAttributesHandler */ -void DomainAttributesHandler::start(Variant::mapType &args) +bool DomainAttributesHandler::start(Variant::mapType &args) { // Fetch the current typesystem and create the struct node Rooted parent = scope().selectOrThrow(); @@ -94,13 +101,14 @@ void DomainAttributesHandler::start(Variant::mapType &args) attrDesc->setLocation(location()); scope().push(attrDesc); + return true; } void DomainAttributesHandler::end() { scope().pop(); } /* DomainFieldHandler */ -void DomainFieldHandler::start(Variant::mapType &args) +bool DomainFieldHandler::start(Variant::mapType &args) { FieldDescriptor::FieldType type; if (args["isSubtree"].asBool()) { @@ -116,13 +124,14 @@ void DomainFieldHandler::start(Variant::mapType &args) field->setLocation(location()); scope().push(field); + return true; } void DomainFieldHandler::end() { scope().pop(); } /* DomainFieldRefHandler */ -void DomainFieldRefHandler::start(Variant::mapType &args) +bool DomainFieldRefHandler::start(Variant::mapType &args) { Rooted parent = scope().selectOrThrow(); @@ -135,13 +144,14 @@ void DomainFieldRefHandler::start(Variant::mapType &args) field.cast(), logger); } }); + return true; } void DomainFieldRefHandler::end() {} /* DomainPrimitiveHandler */ -void DomainPrimitiveHandler::start(Variant::mapType &args) +bool DomainPrimitiveHandler::start(Variant::mapType &args) { Rooted parent = scope().selectOrThrow(); @@ -167,13 +177,14 @@ void DomainPrimitiveHandler::start(Variant::mapType &args) }); scope().push(field); + return true; } void DomainPrimitiveHandler::end() { scope().pop(); } /* DomainChildHandler */ -void DomainChildHandler::start(Variant::mapType &args) +bool DomainChildHandler::start(Variant::mapType &args) { Rooted field = scope().selectOrThrow(); @@ -186,13 +197,12 @@ void DomainChildHandler::start(Variant::mapType &args) child.cast()); } }); + return true; } -void DomainChildHandler::end() {} - /* DomainParentHandler */ -void DomainParentHandler::start(Variant::mapType &args) +bool DomainParentHandler::start(Variant::mapType &args) { Rooted strct = scope().selectOrThrow(); @@ -200,12 +210,14 @@ void DomainParentHandler::start(Variant::mapType &args) new DomainParent(strct->getManager(), args["ref"].asString(), strct)}; parent->setLocation(location()); scope().push(parent); + return true; } void DomainParentHandler::end() { scope().pop(); } /* DomainParentFieldHandler */ -void DomainParentFieldHandler::start(Variant::mapType &args) + +bool DomainParentFieldHandler::start(Variant::mapType &args) { Rooted parentNameNode = scope().selectOrThrow(); FieldDescriptor::FieldType type; @@ -233,13 +245,12 @@ void DomainParentFieldHandler::start(Variant::mapType &args) field->addChild(strct.cast()); } }); + return true; } -void DomainParentFieldHandler::end() {} - /* DomainParentFieldRefHandler */ -void DomainParentFieldRefHandler::start(Variant::mapType &args) +bool DomainParentFieldRefHandler::start(Variant::mapType &args) { Rooted parentNameNode = scope().selectOrThrow(); @@ -265,12 +276,12 @@ void DomainParentFieldRefHandler::start(Variant::mapType &args) field->addChild(strct.cast()); } }); + return true; +} } - -void DomainParentFieldRefHandler::end() {} namespace RttiTypes { -const Rtti DomainParent = - RttiBuilder("DomainParent").parent(&Node); +const Rtti DomainParent = RttiBuilder( + "DomainParent").parent(&Node); } } diff --git a/src/core/parser/stack/DomainHandler.hpp b/src/core/parser/stack/DomainHandler.hpp index 5e8ea60..917d65d 100644 --- a/src/core/parser/stack/DomainHandler.hpp +++ b/src/core/parser/stack/DomainHandler.hpp @@ -19,17 +19,24 @@ /** * @file DomainHandler.hpp * - * @author Andreas Stöckel (astoecke@techfak.uni-bielefeld.de) + * Contains the Handler classes used for parsing Domain descriptors. This + * includes the "domain" tag and all describing tags below the "domain" tag. + * + * @author Benjamin Paaßen (bpaassen@techfak.uni-bielefeld.de) */ #ifndef _OUSIA_DOMAIN_HANDLER_HPP_ #define _OUSIA_DOMAIN_HANDLER_HPP_ #include +#include #include "Handler.hpp" namespace ousia { +namespace parser_stack { + +// TODO: Documentation // Forward declarations class Rtti; @@ -39,7 +46,6 @@ public: using StaticHandler::StaticHandler; bool start(Variant::mapType &args) override; - void end() override; static Handler *create(const HandlerData &handlerData) @@ -53,7 +59,6 @@ public: using StaticHandler::StaticHandler; bool start(Variant::mapType &args) override; - void end() override; static Handler *create(const HandlerData &handlerData) @@ -67,7 +72,6 @@ public: using StaticHandler::StaticHandler; bool start(Variant::mapType &args) override; - void end() override; static Handler *create(const HandlerData &handlerData) @@ -81,7 +85,6 @@ public: using StaticHandler::StaticHandler; bool start(Variant::mapType &args) override; - void end() override; static Handler *create(const HandlerData &handlerData) @@ -95,7 +98,6 @@ public: using StaticHandler::StaticHandler; bool start(Variant::mapType &args) override; - void end() override; static Handler *create(const HandlerData &handlerData) @@ -109,7 +111,6 @@ public: using StaticHandler::StaticHandler; bool start(Variant::mapType &args) override; - void end() override; static Handler *create(const HandlerData &handlerData) @@ -123,7 +124,6 @@ public: using StaticHandler::StaticHandler; bool start(Variant::mapType &args) override; - void end() override; static Handler *create(const HandlerData &handlerData) @@ -138,8 +138,6 @@ public: bool start(Variant::mapType &args) override; - void end() override; - static Handler *create(const HandlerData &handlerData) { return new DomainChildHandler{handlerData}; @@ -160,7 +158,6 @@ public: using StaticHandler::StaticHandler; bool start(Variant::mapType &args) override; - void end() override; static Handler *create(const HandlerData &handlerData) @@ -175,8 +172,6 @@ public: bool start(Variant::mapType &args) override; - void end() override; - static Handler *create(const HandlerData &handlerData) { return new DomainParentFieldHandler{handlerData}; @@ -189,12 +184,15 @@ public: bool start(Variant::mapType &args) override; - void end() override; - static Handler *create(const HandlerData &handlerData) { return new DomainParentFieldRefHandler{handlerData}; } }; } + +namespace RttiTypes { +extern const Rtti DomainParent; +} +} #endif diff --git a/src/core/parser/stack/Handler.cpp b/src/core/parser/stack/Handler.cpp index a608f7f..86000c4 100644 --- a/src/core/parser/stack/Handler.cpp +++ b/src/core/parser/stack/Handler.cpp @@ -65,6 +65,8 @@ Logger &Handler::logger() const SourceLocation &Handler::location() const { return handlerData.location; } +const std::string &Handler::name() const { return handlerData.name; } + void Handler::setWhitespaceMode(WhitespaceMode whitespaceMode) { /*handlerData.callbacks.setWhitespaceMode(whitespaceMode);*/ @@ -80,7 +82,7 @@ void Handler::unregisterToken(const std::string &token) /*handlerData.callbacks.unregisterToken(token);*/ } -const std::string &Handler::getName() const { return handlerData.name; } +const std::string &Handler::getName() const { return name(); } const State &Handler::getState() const { return handlerData.state; } @@ -92,7 +94,7 @@ const SourceLocation &Handler::getLocation() const { return location(); } /* Class EmptyHandler */ -bool EmptyHandler::start(const Variant::mapType &args) +bool EmptyHandler::start(Variant::mapType &args) { // Just accept anything return true; @@ -115,7 +117,7 @@ void EmptyHandler::fieldEnd() } bool EmptyHandler::annotationStart(const Variant &className, - const Variant::mapType &args) + Variant::mapType &args) { // Accept any data return true; @@ -128,7 +130,7 @@ bool EmptyHandler::annotationEnd(const Variant &className, return true; } -bool EmptyHandler::data(const Variant &data) +bool EmptyHandler::data(Variant &data) { // Support any data return true; @@ -141,7 +143,7 @@ Handler *EmptyHandler::create(const HandlerData &handlerData) /* Class StaticHandler */ -bool StaticHandler::start(const Variant::mapType &args) +bool StaticHandler::start(Variant::mapType &args) { // Do nothing in the default implementation, accept anything return true; @@ -169,7 +171,7 @@ void StaticHandler::fieldEnd() } bool StaticHandler::annotationStart(const Variant &className, - const Variant::mapType &args) + Variant::mapType &args) { // No annotations supported return false; @@ -182,7 +184,7 @@ bool StaticHandler::annotationEnd(const Variant &className, return false; } -bool StaticHandler::data(const Variant &data) +bool StaticHandler::data(Variant &data) { logger().error("Did not expect any data here", data); return false; @@ -196,7 +198,7 @@ StaticFieldHandler::StaticFieldHandler(const HandlerData &handlerData, { } -bool StaticFieldHandler::start(const Variant::mapType &args) +bool StaticFieldHandler::start(Variant::mapType &args) { if (!argName.empty()) { auto it = args.find(argName); @@ -225,7 +227,7 @@ void StaticFieldHandler::end() } } -bool StaticFieldHandler::data(const Variant &data) +bool StaticFieldHandler::data(Variant &data) { // Call the doHandle function if this has not been done before if (!handled) { diff --git a/src/core/parser/stack/Handler.hpp b/src/core/parser/stack/Handler.hpp index eeaf555..7cda7a4 100644 --- a/src/core/parser/stack/Handler.hpp +++ b/src/core/parser/stack/Handler.hpp @@ -151,6 +151,13 @@ protected: */ const SourceLocation &location() const; + /** + * Returns the command name for which the handler was created. + * + * @return a const reference at the command name. + */ + const std::string &name() const; + public: /** * Virtual destructor. @@ -229,7 +236,7 @@ public: * @return true if the handler was successful in starting the element it * represents, false otherwise. */ - virtual bool start(const Variant::mapType &args) = 0; + virtual bool start(Variant::mapType &args) = 0; /** * Called before the command for which this handler is defined ends (is @@ -270,7 +277,7 @@ public: * if an error occurred. */ virtual bool annotationStart(const Variant &className, - const Variant::mapType &args) = 0; + Variant::mapType &args) = 0; /** * Called whenever an annotation ends while this handler is active. The @@ -296,7 +303,7 @@ public: * location. * @return true if the data could be handled, false otherwise. */ - virtual bool data(const Variant &data) = 0; + virtual bool data(Variant &data) = 0; }; /** @@ -318,15 +325,15 @@ protected: using Handler::Handler; public: - bool start(const Variant::mapType &args) override; + bool start(Variant::mapType &args) override; void end() override; bool fieldStart(bool &isDefault, size_t fieldIdx) override; void fieldEnd() override; bool annotationStart(const Variant &className, - const Variant::mapType &args) override; + Variant::mapType &args) override; bool annotationEnd(const Variant &className, const Variant &elementName) override; - bool data(const Variant &data) override; + bool data(Variant &data) override; /** * Creates an instance of the EmptyHandler class. @@ -344,15 +351,15 @@ protected: using Handler::Handler; public: - bool start(const Variant::mapType &args) override; + bool start(Variant::mapType &args) override; void end() override; bool fieldStart(bool &isDefault, size_t fieldIdx) override; void fieldEnd() override; bool annotationStart(const Variant &className, - const Variant::mapType &args) override; + Variant::mapType &args) override; bool annotationEnd(const Variant &className, const Variant &elementName) override; - bool data(const Variant &data) override; + bool data(Variant &data) override; }; /** @@ -400,12 +407,12 @@ protected: * @param args are the arguments that were given in the "start" function. */ virtual void doHandle(const Variant &fieldData, - const Variant::mapType &args) = 0; + Variant::mapType &args) = 0; public: - bool start(const Variant::mapType &args) override; + bool start(Variant::mapType &args) override; void end() override; - bool data(const Variant &data) override; + bool data(Variant &data) override; }; } } diff --git a/src/core/parser/stack/ImportIncludeHandler.cpp b/src/core/parser/stack/ImportIncludeHandler.cpp index 94ee82d..797dd8d 100644 --- a/src/core/parser/stack/ImportIncludeHandler.cpp +++ b/src/core/parser/stack/ImportIncludeHandler.cpp @@ -18,48 +18,16 @@ #include "ImportIncludeHandler.hpp" +#include #include +#include 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); -} +namespace parser_stack { /* 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() +void ImportHandler::doHandle(const Variant &fieldData, Variant::mapType &args) { // Fetch the last node and check whether an import is valid at this // position @@ -75,8 +43,9 @@ void ImportHandler::end() // Perform the actual import, register the imported node within the leaf // node - Rooted imported = - context().import(src, type, rel, leafRootNode->getReferenceTypes()); + Rooted imported = context().import( + fieldData.asString(), args["type"].asString(), args["rel"].asString(), + leafRootNode->getReferenceTypes()); if (imported != nullptr) { leafRootNode->reference(imported); } @@ -84,13 +53,10 @@ void ImportHandler::end() /* IncludeHandler */ -void IncludeHandler::start(Variant::mapType &args) +void IncludeHandler::doHandle(const Variant &fieldData, Variant::mapType &args) { - ImportIncludeHandler::start(args); + context().include(fieldData.asString(), args["type"].asString(), + args["rel"].asString(), {&RttiTypes::Node}); } - -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 index f9abe55..8f3d3d0 100644 --- a/src/core/parser/stack/ImportIncludeHandler.hpp +++ b/src/core/parser/stack/ImportIncludeHandler.hpp @@ -29,9 +29,11 @@ #define _OUSIA_IMPORT_INCLUDE_HANDLER_HPP_ #include -#include + +#include "Handler.hpp" namespace ousia { +namespace parser_stack { /** * The ImportHandler is responsible for handling the "import" command. An import @@ -46,7 +48,7 @@ public: using StaticFieldHandler::StaticFieldHandler; void doHandle(const Variant &fieldData, - const Variant::mapType &args) override; + Variant::mapType &args) override; /** * Creates a new instance of the ImportHandler. @@ -57,7 +59,7 @@ public: */ static Handler *create(const HandlerData &handlerData) { - return new ImportHandler{handlerData}; + return new ImportHandler{handlerData, "src"}; } }; @@ -72,7 +74,7 @@ public: using StaticFieldHandler::StaticFieldHandler; void doHandle(const Variant &fieldData, - const Variant::mapType &args) override; + Variant::mapType &args) override; /** * Creates a new instance of the IncludeHandler. @@ -83,8 +85,9 @@ public: */ static Handler *create(const HandlerData &handlerData) { - return new IncludeHandler{handlerData}; + return new IncludeHandler{handlerData, "src"}; } }; } +} #endif diff --git a/src/core/parser/stack/Stack.cpp b/src/core/parser/stack/Stack.cpp index d84a19c..47f7d2c 100644 --- a/src/core/parser/stack/Stack.cpp +++ b/src/core/parser/stack/Stack.cpp @@ -316,8 +316,6 @@ void Stack::command(const Variant &name, const Variant::mapType &args) name); } - State const *lastTargetState = nullptr; - Variant::mapType canonicalArgs; while (true) { // Try to find a target state for the given command, if none can be // found and the current command does not have an open field, then try @@ -342,14 +340,6 @@ void Stack::command(const Variant &name, const Variant::mapType &args) // Fork the logger. We do not want any validation errors to skip LoggerFork loggerFork = logger().fork(); - // Canonicalize the arguments (if this has not already been done), allow - // additional arguments - if (lastTargetState != targetState) { - canonicalArgs = args; - targetState->arguments.validateMap(canonicalArgs, loggerFork, true); - lastTargetState = targetState; - } - // Instantiate the handler and push it onto the stack HandlerConstructor ctor = targetState->elementHandler ? targetState->elementHandler @@ -369,6 +359,11 @@ void Stack::command(const Variant &name, const Variant::mapType &args) bool validStack = handlersValid(); info.valid = false; if (validStack) { + // Canonicalize the arguments (if this has not already been done), + // allow additional arguments + Variant::mapType canonicalArgs = args; + targetState->arguments.validateMap(canonicalArgs, loggerFork, true); + handler->setLogger(loggerFork); try { info.valid = handler->start(canonicalArgs); @@ -430,7 +425,8 @@ void Stack::data(const Variant &data) // Pass the data to the current Handler instance bool valid = false; try { - valid = info.handler->data(data); + Variant dataCopy = data; + valid = info.handler->data(dataCopy); } catch (LoggableException ex) { loggerFork.log(ex); diff --git a/src/core/parser/stack/TypesystemHandler.cpp b/src/core/parser/stack/TypesystemHandler.cpp index 2cc7dfb..34f64f9 100644 --- a/src/core/parser/stack/TypesystemHandler.cpp +++ b/src/core/parser/stack/TypesystemHandler.cpp @@ -20,28 +20,33 @@ #include #include +#include + namespace ousia { +namespace parser_stack { /* TypesystemHandler */ -void TypesystemHandler::start(Variant::mapType &args) +bool TypesystemHandler::start(Variant::mapType &args) { // Create the typesystem instance Rooted typesystem = - project()->createTypesystem(args["name"].asString()); + context().getProject()->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); + + return true; } void TypesystemHandler::end() { scope().pop(); } /* TypesystemEnumHandler */ -void TypesystemEnumHandler::start(Variant::mapType &args) +bool TypesystemEnumHandler::start(Variant::mapType &args) { scope().setFlag(ParserFlag::POST_HEAD, true); @@ -52,33 +57,24 @@ void TypesystemEnumHandler::start(Variant::mapType &args) enumType->setLocation(location()); scope().push(enumType); + + return true; } void TypesystemEnumHandler::end() { scope().pop(); } /* TypesystemEnumEntryHandler */ -void TypesystemEnumEntryHandler::start(Variant::mapType &args) {} - -void TypesystemEnumEntryHandler::end() +void TypesystemEnumEntryHandler::doHandle(const Variant &fieldData, + Variant::mapType &args) { Rooted enumType = scope().selectOrThrow(); - 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); + enumType->addEntry(fieldData.asString(), logger()); } /* TypesystemStructHandler */ -void TypesystemStructHandler::start(Variant::mapType &args) +bool TypesystemStructHandler::start(Variant::mapType &args) { scope().setFlag(ParserFlag::POST_HEAD, true); @@ -103,13 +99,15 @@ void TypesystemStructHandler::start(Variant::mapType &args) }); } scope().push(structType); + + return true; } void TypesystemStructHandler::end() { scope().pop(); } /* TypesystemStructFieldHandler */ -void TypesystemStructFieldHandler::start(Variant::mapType &args) +bool TypesystemStructFieldHandler::start(Variant::mapType &args) { // Read the argument values const std::string &name = args["name"].asString(); @@ -142,13 +140,13 @@ void TypesystemStructFieldHandler::start(Variant::mapType &args) } }); } -} -void TypesystemStructFieldHandler::end() {} + return true; +} /* TypesystemConstantHandler */ -void TypesystemConstantHandler::start(Variant::mapType &args) +bool TypesystemConstantHandler::start(Variant::mapType &args) { scope().setFlag(ParserFlag::POST_HEAD, true); @@ -169,7 +167,9 @@ void TypesystemConstantHandler::start(Variant::mapType &args) constant.cast()->setType(type.cast(), logger); } }); -} -void TypesystemConstantHandler::end() {} + return true; } +} +} + diff --git a/src/core/parser/stack/TypesystemHandler.hpp b/src/core/parser/stack/TypesystemHandler.hpp index 76a7bc9..55277a1 100644 --- a/src/core/parser/stack/TypesystemHandler.hpp +++ b/src/core/parser/stack/TypesystemHandler.hpp @@ -19,6 +19,9 @@ /** * @file TypesystemHandler.hpp * + * Contains the Handler classes used to parse Typesystem descriptions. The + * Handlers parse all the tags found below and including the "typesystem" tag. + * * @author Andreas Stöckel (astoecke@techfak.uni-bielefeld.de) */ @@ -26,96 +29,154 @@ #define _OUSIA_TYPESYSTEM_HANDLER_HPP_ #include -#include + +#include "Handler.hpp" namespace ousia { +namespace parser_stack { -class TypesystemHandler : public Handler { +/** + * Handles the occurance of the "typesystem" tag. Creates a new Typesystem + * instance and places it on the ParserScope. + */ +class TypesystemHandler : public StaticHandler { public: - using Handler::Handler; - - void start(Variant::mapType &args) override; + using StaticHandler::StaticHandler; + bool start(Variant::mapType &args) override; void end() override; + /** + * Creates a new instance of the TypesystemHandler. + * + * @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 TypesystemHandler{handlerData}; } }; -class TypesystemEnumHandler : public Handler { +/** + * Handles the occurance of the "enum" tag. Creates a new EnumType instance and + * places it on the ParserScope. + */ +class TypesystemEnumHandler : public StaticHandler { public: - using Handler::Handler; - - void start(Variant::mapType &args) override; + using StaticHandler::StaticHandler; + bool start(Variant::mapType &args) override; void end() override; + /** + * Creates a new instance of the TypesystemEnumHandler. + * + * @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 TypesystemEnumHandler{handlerData}; } }; -class TypesystemEnumEntryHandler : public Handler { +/** + * Handles the occurance of the "entry" tag within an "enum" tag. Creates a new + * EnumType instance and places it on the ParserScope. + */ +class TypesystemEnumEntryHandler : public StaticFieldHandler { 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; - + using StaticFieldHandler::StaticFieldHandler; + + void doHandle(const Variant &fieldData, + Variant::mapType &args) override; + + /** + * Creates a new instance of the TypesystemEnumEntryHandler. + * + * @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 TypesystemEnumEntryHandler{handlerData}; + return new TypesystemEnumEntryHandler{handlerData, "name"}; } }; -class TypesystemStructHandler : public Handler { +/** + * Handles the occurance of the "struct" tag within a typesystem description. + * Creates a new StructType instance and places it on the ParserScope. + */ +class TypesystemStructHandler : public StaticHandler { public: - using Handler::Handler; - - void start(Variant::mapType &args) override; + using StaticHandler::StaticHandler; + bool start(Variant::mapType &args) override; void end() override; + /** + * Creates a new instance of the TypesystemStructHandler. + * + * @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 TypesystemStructHandler{handlerData}; } }; -class TypesystemStructFieldHandler : public Handler { +/** + * Handles the occurance of the "field" tag within a typesystem structure + * description. Places a new Attribute instance in the StructType instance + * that is currently at the top of the scope. + */ +class TypesystemStructFieldHandler : public StaticHandler { public: - using Handler::Handler; + using StaticHandler::StaticHandler; - void start(Variant::mapType &args) override; - - void end() override; + bool start(Variant::mapType &args) override; + /** + * Creates a new instance of the TypesystemStructFieldHandler. + * + * @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 TypesystemStructFieldHandler{handlerData}; } }; -class TypesystemConstantHandler : public Handler { +/** + * Handles the occurance of the "constant" tag within a typesystem structure + * description. Places a new Constant instance in the current typesystem. + */ +class TypesystemConstantHandler : public StaticHandler { public: - using Handler::Handler; + using StaticHandler::StaticHandler; - void start(Variant::mapType &args) override; - - void end() override; + bool start(Variant::mapType &args) override; + /** + * Creates a new instance of the TypesystemConstantHandler. + * + * @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 TypesystemConstantHandler{handlerData}; } }; } +} #endif diff --git a/test/core/parser/stack/StackTest.cpp b/test/core/parser/stack/StackTest.cpp index 7cc8bc5..321d471 100644 --- a/test/core/parser/stack/StackTest.cpp +++ b/test/core/parser/stack/StackTest.cpp @@ -112,16 +112,21 @@ private: TestHandler(const HandlerData &handlerData) : Handler(handlerData) {} public: - bool start(const Variant::mapType &args) + bool start(Variant::mapType &args) override { tracker.startCount++; tracker.startArgs = args; + if (!tracker.startResult) { + logger().error( + "The TestHandler was told not to allow a field start. So it " + "doesn't. The TestHandler always obeys its master."); + } return tracker.startResult; } - void end() { tracker.endCount++; } + void end() override { tracker.endCount++; } - bool fieldStart(bool &isDefault, size_t fieldIdx) + bool fieldStart(bool &isDefault, size_t fieldIdx) override { tracker.fieldStartCount++; tracker.fieldStartIsDefault = isDefault; @@ -132,9 +137,10 @@ public: return tracker.fieldStartResult; } - void fieldEnd() { tracker.fieldEndCount++; } + void fieldEnd() override { tracker.fieldEndCount++; } - bool annotationStart(const Variant &className, const Variant::mapType &args) + bool annotationStart(const Variant &className, + Variant::mapType &args) override { tracker.annotationStartCount++; tracker.annotationStartClassName = className; @@ -142,7 +148,8 @@ public: return tracker.annotationStartResult; } - bool annotationEnd(const Variant &className, const Variant &elementName) + bool annotationEnd(const Variant &className, + const Variant &elementName) override { tracker.annotationEndCount++; tracker.annotationEndClassName = className; @@ -150,7 +157,7 @@ public: return tracker.annotationEndResult; } - bool data(const Variant &data) + bool data(Variant &data) override { tracker.dataCount++; tracker.dataData = data; @@ -458,6 +465,26 @@ TEST(Stack, noImplicitDefaultFieldIfDefaultFieldGiven) ASSERT_FALSE(logger.hasError()); } +TEST(Stack, noEndIfStartFails) +{ + tracker.reset(); + logger.reset(); + { + Stack s{env.context, States::AnyHandlers}; + + s.command("a", {}); + tracker.expect(1, 0, 0, 0, 0, 0, 0); // sc, ec, fsc, fse, asc, aec, dc + ASSERT_EQ("a", s.currentCommandName()); + + tracker.startResult = false; + s.command("b", {}); + tracker.expect(3, 1, 1, 1, 0, 0, 0); // sc, ec, fsc, fse, asc, aec, dc + ASSERT_EQ("b", s.currentCommandName()); + } + tracker.expect(3, 1, 1, 1, 0, 0, 0); // sc, ec, fsc, fse, asc, aec, dc + ASSERT_TRUE(logger.hasError()); +} + TEST(Stack, implicitDefaultFieldOnData) { tracker.reset(); -- cgit v1.2.3 From 40f4666c43211d9071a827ad8a2524688e7f678f Mon Sep 17 00:00:00 2001 From: Andreas Stöckel Date: Sun, 15 Feb 2015 20:59:12 +0100 Subject: Fixed StaticFieldHandler using empty strings --- src/core/parser/stack/Handler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/core/parser/stack/Handler.cpp') diff --git a/src/core/parser/stack/Handler.cpp b/src/core/parser/stack/Handler.cpp index 86000c4..bf5d4ea 100644 --- a/src/core/parser/stack/Handler.cpp +++ b/src/core/parser/stack/Handler.cpp @@ -202,7 +202,7 @@ bool StaticFieldHandler::start(Variant::mapType &args) { if (!argName.empty()) { auto it = args.find(argName); - if (it != args.end()) { + if (it != args.end() && !it->second.toString().empty()) { handled = true; doHandle(it->second, args); return true; -- cgit v1.2.3