diff options
author | Andreas Stöckel <astoecke@techfak.uni-bielefeld.de> | 2015-02-15 00:07:58 +0100 |
---|---|---|
committer | Andreas Stöckel <astoecke@techfak.uni-bielefeld.de> | 2015-02-15 00:07:58 +0100 |
commit | cc281d91def921b7bbf5d3d4a0fce53afc5a317b (patch) | |
tree | 3ea32f91e35df73d12ce6742436db87440347cb9 | |
parent | 40e5867bdf347dede1f6b593b774334ca17fd09d (diff) |
Renamed parser/generic to parser/stack and made filenames much shorter
-rw-r--r-- | src/core/parser/generic/ParserStateHandler.cpp | 104 | ||||
-rw-r--r-- | src/core/parser/stack/Callbacks.cpp (renamed from src/core/parser/generic/ParserStateCallbacks.cpp) | 5 | ||||
-rw-r--r-- | src/core/parser/stack/Callbacks.hpp (renamed from src/core/parser/generic/ParserStateCallbacks.hpp) | 27 | ||||
-rw-r--r-- | src/core/parser/stack/Handler.cpp | 90 | ||||
-rw-r--r-- | src/core/parser/stack/Handler.hpp (renamed from src/core/parser/generic/ParserStateHandler.hpp) | 195 | ||||
-rw-r--r-- | src/core/parser/stack/Stack.cpp (renamed from src/core/parser/generic/ParserStateStack.cpp) | 51 | ||||
-rw-r--r-- | src/core/parser/stack/Stack.hpp (renamed from src/core/parser/generic/ParserStateStack.hpp) | 0 | ||||
-rw-r--r-- | src/core/parser/stack/State.cpp (renamed from src/core/parser/generic/ParserState.cpp) | 66 | ||||
-rw-r--r-- | src/core/parser/stack/State.hpp (renamed from src/core/parser/generic/ParserState.hpp) | 151 | ||||
-rw-r--r-- | test/core/parser/ParserStateTest.cpp | 77 | ||||
-rw-r--r-- | test/core/parser/stack/StateTest.cpp | 79 |
11 files changed, 439 insertions, 406 deletions
diff --git a/src/core/parser/generic/ParserStateHandler.cpp b/src/core/parser/generic/ParserStateHandler.cpp deleted file mode 100644 index 64e2bfa..0000000 --- a/src/core/parser/generic/ParserStateHandler.cpp +++ /dev/null @@ -1,104 +0,0 @@ -/* - Ousía - Copyright (C) 2014, 2015 Benjamin Paaßen, Andreas Stöckel - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - -#include <core/parser/ParserContext.hpp> - -#include "ParserStateHandler.hpp" - -namespace ousia { - -/* Class ParserStatedata */ - -ParserStatedata::ParserStatedata(ParserContext &ctx, - ParserStateCallbacks &callbacks, - std::string name, const ParserState &state, - const ParserState &parentState, - const SourceLocation location) - : ctx(ctx), - callbacks(callbacks), - name(std::move(name)), - state(state), - parentState(parentState), - location(location){}; - -/* Class ParserStateHandler */ - -ParserStateHandler::ParserStateHandler(const ParserStatedata &data) : data(data) -{ -} - -ParserContext &ParserStateHandler::context() { return data.ctx; } - -const std::string &ParserStateHandler::name() { return data.name; } - -ParserScope &ParserStateHandler::scope() { return data.ctx.getScope(); } - -Manager &ParserStateHandler::manager() { return data.ctx.getManager(); } - -Logger &ParserStateHandler::logger() { return data.ctx.getLogger(); } - -Rooted<Project> ParserStateHandler::project() { return data.ctx.getProject(); } - -const ParserState &ParserStateHandler::state() { return data.state; } - -SourceLocation ParserStateHandler::location() { return data.location; } - -void ParserStateHandler::setWhitespaceMode(WhitespaceMode whitespaceMode) -{ - data.callbacks.setWhitespaceMode(whitespaceMode); -} - -void ParserStateHandler::setDataType(VariantType type) -{ - data.callbacks.setDataType(type); -} - -bool ParserStateHandler::supportsToken(const std::string &token) -{ - return data.callbacks.supportsToken(token); -} - -void ParserStateHandler::registerToken(const std::string &token) -{ - data.callbacks.registerToken(token); -} - -void ParserStateHandler::unregisterToken(const std::string &token) -{ - data.callbacks.unregisterToken(token); -} - -void ParserStateHandler::data(const std::string &data, int field) -{ - if (Utils::hasNonWhitepaceChar(data)) { - logger().error("Expected command but found character data."); - } -} - -/* Class DefaultParserStateHandler */ - -void DefaultParserStateHandler::start(Variant::mapType &args) {} - -void DefaultParserStateHandler::end() {} - -ParserStateHandler *DefaultParserStateHandler::create(const data &data) -{ - return new DefaultHandler{data}; -} -} - diff --git a/src/core/parser/generic/ParserStateCallbacks.cpp b/src/core/parser/stack/Callbacks.cpp index 50bac57..6ebc549 100644 --- a/src/core/parser/generic/ParserStateCallbacks.cpp +++ b/src/core/parser/stack/Callbacks.cpp @@ -16,11 +16,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include <ParserStateCallbacks.hpp> +#include "Callbacks.hpp" namespace ousia { - -/* Class ParserStateCallbacks */ - } diff --git a/src/core/parser/generic/ParserStateCallbacks.hpp b/src/core/parser/stack/Callbacks.hpp index 7ec5264..bb56e44 100644 --- a/src/core/parser/generic/ParserStateCallbacks.hpp +++ b/src/core/parser/stack/Callbacks.hpp @@ -17,10 +17,10 @@ */ /** - * @file ParserStateCallbacks.hpp + * @file Callbacks.hpp * * Contains an interface defining the callbacks that can be directed from a - * ParserStateHandler to the ParserStateStack, and from the ParserStateStack to + * StateHandler to the StateStack, and from the StateStack to * the actual parser. * * @author Andreas Stöckel (astoecke@techfak.uni-bielefeld.de) @@ -34,17 +34,18 @@ #include <core/common/Whitespace.hpp> namespace ousia { +namespace parser_stack { /** * Interface defining a set of callback functions that act as a basis for the - * ParserStateStackCallbacks and the ParserCallbacks. + * StateStackCallbacks and the ParserCallbacks. */ -class ParserStateCallbacks { +class Callbacks { public: /** * Virtual descructor. */ - virtual ~ParserStateCallbacks() {}; + virtual ~Callbacks() {}; /** * Sets the whitespace mode that specifies how string data should be @@ -56,15 +57,6 @@ public: virtual void setWhitespaceMode(WhitespaceMode whitespaceMode) = 0; /** - * Sets the type as which the variant data should be parsed. - * - * @param type is one of the VariantType constants, specifying with which - * type the data that is passed to the ParserStateHandler in the "data" - * function should be handled. - */ - virtual void setDataType(VariantType type) = 0; - - /** * Registers the given token as token that should be reported to the handler * using the "token" function. * @@ -83,9 +75,9 @@ public: /** * Interface defining the callback functions that can be passed from a - * ParserStateStack to the underlying parser. + * StateStack to the underlying parser. */ -class ParserCallbacks : public ParserStateCallbacks { +class ParserCallbacks : public Callbacks { /** * Checks whether the given token is supported by the parser. The parser * returns true, if the token is supported, false if this token cannot be @@ -98,9 +90,10 @@ class ParserCallbacks : public ParserStateCallbacks { * because e.g. it is a reserved token or it interferes with other tokens. */ virtual bool supportsToken(const std::string &token) = 0; -} +}; } +} #endif /* _OUSIA_PARSER_STATE_CALLBACKS_HPP_ */ 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 <http://www.gnu.org/licenses/>. +*/ + +#include <core/parser/ParserContext.hpp> + +#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}; +}*/ +} +} + diff --git a/src/core/parser/generic/ParserStateHandler.hpp b/src/core/parser/stack/Handler.hpp index f3c836e..0701343 100644 --- a/src/core/parser/generic/ParserStateHandler.hpp +++ b/src/core/parser/stack/Handler.hpp @@ -22,20 +22,27 @@ #include <memory> #include <string> -#include <core/utils/Location.hpp> +#include <core/common/Location.hpp> +#include <core/common/Variant.hpp> namespace ousia { // Forward declarations class ParserContext; -class ParserState; -class ParserStateCallbacks; +class Callbacks; +class Logger; +class Project; + +namespace parser_stack { + +// More forward declarations +class State; /** - * Class collecting all the data that is being passed to a ParserStateHandler + * Class collecting all the data that is being passed to a Handler * instance. */ -class ParserStateHandlerData { +class HandlerData { public: /** * Reference to the ParserContext instance that should be used to resolve @@ -44,60 +51,52 @@ public: ParserContext &ctx; /** - * Reference at an instance of the ParserStateCallbacks class, used for + * Reference at an instance of the Callbacks class, used for * modifying the behaviour of the parser (like registering tokens, setting * the data type or changing the whitespace handling mode). */ - ParserStateCallbacks &callbacks; + Callbacks &callbacks; /** * Contains the name of the command that is being handled. */ - const std::string name; + std::string name; /** * Contains the current state of the state machine. */ - const ParserState &state; - - /** - * Contains the state of the state machine when the parent node was handled. - */ - const ParserState &parentState; + const State &state; /** * Current source code location. */ - const SourceLocation location; + SourceLocation location; /** * Constructor of the HandlerData class. * * @param ctx is the parser context the handler should be executed in. - * @param callbacks is an instance of ParserStateCallbacks used to notify + * @param callbacks is an instance of Callbacks used to notify * the parser about certain state changes. * @param name is the name of the string. * @param state is the state this handler was called for. - * @param parentState is the state of the parent command. * @param location is the location at which the handler is created. */ - ParserStateHandlerData(ParserContext &ctx, ParserStateCallbacks &callbacks, - std::string name, const ParserState &state, - const ParserState &parentState, - const SourceLocation &location); + HandlerData(ParserContext &ctx, Callbacks &callbacks, std::string name, + const State &state, const SourceLocation &location); }; /** - * The handler class provides a context for handling an XML tag. It has to be - * overridden and registered in the StateStack class to form handlers for - * concrete XML tags. + * The Handler class provides a context for handling a generic stack element. + * It has to beoverridden and registered in the StateStack class to form + * handlers for concrete XML tags. */ -class ParserStateHandler { +class Handler { private: /** * Structure containing the internal handler data. */ - const ParserStateHandlerData data; + const HandlerData internalData; protected: /** @@ -106,13 +105,7 @@ protected: * @param data is a structure containing all data being passed to the * handler. */ - ParserStateHandler(const ParserStateHandlerData &data){}; - -public: - /** - * Virtual destructor. - */ - virtual ~Handler(){}; + Handler(const HandlerData &internalData); /** * Returns a reference at the ParserContext. @@ -151,20 +144,11 @@ public: Logger &logger(); /** - * Returns a reference at the Project Node, representing the project into - * which the file is currently being parsed. - * - * @return a referance at the Project Node. - */ - Rooted<Project> project(); - - /** - * Reference at the ParserState descriptor for which this Handler was - * created. + * Reference at the State descriptor for which this Handler was created. * - * @return a const reference at the constructing ParserState descriptor. + * @return a const reference at the constructing State descriptor. */ - const ParserState &state(); + const State &state(); /** * Returns the current location in the source file. @@ -173,42 +157,25 @@ public: */ SourceLocation location(); +public: /** - * Calls the corresponding function in the ParserStateCallbacks instance. - * Sets the whitespace mode that specifies how string data should be - * processed. - * - * @param whitespaceMode specifies one of the three WhitespaceMode constants - * PRESERVE, TRIM or COLLAPSE. - */ - void setWhitespaceMode(WhitespaceMode whitespaceMode); - - /** - * Calls the corresponding function in the ParserStateCallbacks instance. - * Sets the type as which the variant data should be parsed. - * - * @param type is one of the VariantType constants, specifying with which - * type the data that is passed to the ParserStateHandler in the "data" - * function should be handled. + * Virtual destructor. */ - void setDataType(VariantType type); + virtual ~Handler(); /** - * Calls the corresponding function in the ParserStateCallbacks instance. - * Checks whether the given token is supported by the parser. The parser - * returns true, if the token is supported, false if this token cannot be - * registered. Note that parsers that do not support the registration of - * tokens at all should always return "true". + * Calls the corresponding function in the Callbacks instance. Sets the + * whitespace mode that specifies how string data should be processed. The + * calls to this function are placed on a stack by the underlying Stack + * class. * - * @param token is the token that should be checked for support. - * @return true if the token is generally supported (or the parser does not - * support registering tokens at all), false if the token is not supported, - * because e.g. it is a reserved token or it interferes with other tokens. + * @param whitespaceMode specifies one of the three WhitespaceMode constants + * PRESERVE, TRIM or COLLAPSE. */ - bool supportsToken(const std::string &token); + void setWhitespaceMode(WhitespaceMode whitespaceMode); /** - * Calls the corresponding function in the ParserStateCallbacks instance. + * Calls the corresponding function in the Callbacks instance. * Registers the given token as token that should be reported to the handler * using the "token" function. * @@ -217,7 +184,7 @@ public: void registerToken(const std::string &token); /** - * Calls the corresponding function in the ParserStateCallbacks instance. + * Calls the corresponding function in the Callbacks instance. * Unregisters the given token, it will no longer be reported to the handler * using the "token" function. * @@ -230,25 +197,77 @@ public: * instanciated. * * @param args is a map from strings to variants (argument name and value). + * @return true if the handler was successful in starting the element it + * represents, false otherwise. */ - virtual void start(Variant::mapType &args) = 0; + virtual bool start(Variant::mapType &args) = 0; /** - * Called whenever the command for which this handler is defined ends. + * Called before the command for which this handler is defined ends (is + * forever removed from the stack). */ virtual void end() = 0; /** - * Called whenever raw data (int the form of a string) is available for the - * Handler instance. In the default handler an exception is raised if the - * received data contains non-whitespace characters. + * Called when a new field starts, while the handler is active. This + * function should return true if the field is supported, false otherwise. + * No error should be logged if the field cannot be started, the caller will + * take care of that (since it is always valid to start a default field, + * 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. + */ + virtual bool fieldStart(bool &isDefaultField, bool isImplicit, + size_t fieldIndex) = 0; + + /** + * Called when a previously opened field ends, while the handler is active. + * Note that a "fieldStart" and "fieldEnd" are always called alternately. + */ + virtual void fieldEnd() = 0; + + /** + * Called whenever an annotation starts while this handler is active. The + * function should return true if starting the annotation was successful, + * false otherwise. + * + * @param className is a string variant containing the name of the + * annotation class and the location of the name in the source code. + * @param args is a map from strings to variants (argument name and value). + * @return true if the mentioned annotation could be started here, false + * if an error occurred. + */ + virtual bool annotationStart(Variant className, Variant::mapType &args) = 0; + + /** + * Called whenever an annotation ends while this handler is active. The + * function should return true if ending the annotation was successful, + * false otherwise. * - * @param data is a pointer at the character data that is available for the + * @param className is a string variant containing the name of the + * annotation class and the location of the class name in the source code. + * @param elementName is a string variant containing the name of the + * annotation class and the location of the element name in the source code. + * @return true if the mentioned annotation could be started here, false if + * an error occurred. + */ + virtual bool annotationEnd(Variant className, Variant elementName) = 0; + + /** + * Called whenever raw data (int the form of a string) is available for the * Handler instance. - * @param field is the field number (the interpretation of this value - * depends on the format that is being parsed). + * + * @param data is a string variant containing the character data and its + * location. */ - virtual void data(const std::string &data, int field); + virtual void data(Variant data) = 0; }; /** @@ -263,18 +282,20 @@ using HandlerConstructor = Handler *(*)(const HandlerData &handlerData); /** * The DefaultHandler class is used in case no element handler is specified in - * the ParserState descriptor. + * the State descriptor. */ -class DefaultParserStateHandler : public ParserStateHandler { +/*class EmptyHandler : public Handler { public: - using ParserStateHandler::ParserStateHandler; + using Handler::Handler; void start(Variant::mapType &args) override; void end() override; static Handler *create(const HandlerData &handlerData); -}; +};*/ + +} } #endif /* _OUSIA_PARSER_STATE_HANDLER_HPP_ */ diff --git a/src/core/parser/generic/ParserStateStack.cpp b/src/core/parser/stack/Stack.cpp index 8c32f17..1d83a68 100644 --- a/src/core/parser/generic/ParserStateStack.cpp +++ b/src/core/parser/stack/Stack.cpp @@ -20,14 +20,14 @@ #include <core/common/Utils.hpp> #include <core/common/Exceptions.hpp> -#include <core/model/Project.hpp> +#include <core/parser/ParserScope.hpp> -#include "ParserScope.hpp" -#include "ParserStateStack.hpp" +#include "Stack.hpp" namespace ousia { +namespace parser_stack { -/* Class ParserStateStack */ +/* Class StateStack */ /** * Returns an Exception that should be thrown when a currently invalid command @@ -50,25 +50,25 @@ static LoggableException InvalidCommand(const std::string &name, } } -ParserStateStack::ParserStateStack( +StateStack::StateStack( ParserContext &ctx, - const std::multimap<std::string, const ParserState *> &states) + const std::multimap<std::string, const State *> &states) : ctx(ctx), states(states) { } -bool ParserStateStack::deduceState() +bool StateStack::deduceState() { // Assemble all states - std::vector<const ParserState *> states; + std::vector<const State *> states; for (const auto &e : this->states) { states.push_back(e.second); } // Fetch the type signature of the scope and derive all possible states, // abort if no unique parser state was found - std::vector<const ParserState *> possibleStates = - ParserStateDeductor(ctx.getScope().getStackTypeSignature(), states) + std::vector<const State *> possibleStates = + StateDeductor(ctx.getScope().getStackTypeSignature(), states) .deduce(); if (possibleStates.size() != 1) { ctx.getLogger().error( @@ -77,16 +77,16 @@ bool ParserStateStack::deduceState() } // Switch to this state by creating a dummy handler - const ParserState *state = possibleStates[0]; + const State *state = possibleStates[0]; Handler *handler = DefaultHandler::create({ctx, "", *state, *state, SourceLocation{}}); stack.emplace(handler); return true; } -std::set<std::string> ParserStateStack::expectedCommands() +std::set<std::string> StateStack::expectedCommands() { - const ParserState *currentState = &(this->currentState()); + const State *currentState = &(this->currentState()); std::set<std::string> res; for (const auto &v : states) { if (v.second->parents.count(currentState)) { @@ -96,23 +96,23 @@ std::set<std::string> ParserStateStack::expectedCommands() return res; } -const ParserState &ParserStateStack::currentState() +const State &StateStack::currentState() { - return stack.empty() ? ParserStates::None : stack.top()->state(); + return stack.empty() ? States::None : stack.top()->state(); } -std::string ParserStateStack::currentCommandName() +std::string StateStack::currentCommandName() { return stack.empty() ? std::string{} : stack.top()->name(); } -const ParserState *ParserStateStack::findTargetState(const std::string &name) +const State *StateStack::findTargetState(const std::string &name) { - const ParserState *currentState = &(this->currentState()); + const State *currentState = &(this->currentState()); auto range = states.equal_range(name); for (auto it = range.first; it != range.second; it++) { - const ParserStateSet &parents = it->second->parents; - if (parents.count(currentState) || parents.count(&ParserStates::All)) { + const StateSet &parents = it->second->parents; + if (parents.count(currentState) || parents.count(&States::All)) { return it->second; } } @@ -120,10 +120,10 @@ const ParserState *ParserStateStack::findTargetState(const std::string &name) return nullptr; } -void ParserStateStack::start(const std::string &name, Variant::mapType &args, +void StateStack::start(const std::string &name, Variant::mapType &args, const SourceLocation &location) { - ParserState const *targetState = findTargetState(name); + State const *targetState = findTargetState(name); // TODO: Andreas, please improve this. // if (!Utils::isIdentifier(name)) { // throw LoggableException(std::string("Invalid identifier \"") + name + @@ -151,14 +151,14 @@ void ParserStateStack::start(const std::string &name, Variant::mapType &args, stack.emplace(handler); } -void ParserStateStack::start(std::string name, const Variant::mapType &args, +void StateStack::start(std::string name, const Variant::mapType &args, const SourceLocation &location) { Variant::mapType argsCopy(args); start(name, argsCopy); } -void ParserStateStack::end() +void StateStack::end() { // Check whether the current command could be ended if (stack.empty()) { @@ -173,7 +173,7 @@ void ParserStateStack::end() inst->end(); } -void ParserStateStack::data(const std::string &data, int field) +void StateStack::data(const std::string &data, int field) { // Check whether there is any command the data can be sent to if (stack.empty()) { @@ -184,4 +184,5 @@ void ParserStateStack::data(const std::string &data, int field) stack.top()->data(data, field); } } +} diff --git a/src/core/parser/generic/ParserStateStack.hpp b/src/core/parser/stack/Stack.hpp index b106475..b106475 100644 --- a/src/core/parser/generic/ParserStateStack.hpp +++ b/src/core/parser/stack/Stack.hpp diff --git a/src/core/parser/generic/ParserState.cpp b/src/core/parser/stack/State.cpp index f635d86..d72f533 100644 --- a/src/core/parser/generic/ParserState.cpp +++ b/src/core/parser/stack/State.cpp @@ -16,88 +16,97 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "ParserState.hpp" +#include "State.hpp" namespace ousia { +namespace parser_stack { -/* Class ParserState */ +/* Class State */ -ParserState::ParserState() : elementHandler(nullptr) {} +State::State() : elementHandler(nullptr) {} -ParserState::ParserState(ParserStateSet parents, Arguments arguments, +State::State(StateSet parents, Arguments arguments, RttiSet createdNodeTypes, - HandlerConstructor elementHandler) + HandlerConstructor elementHandler, + bool supportsAnnotations) : parents(parents), arguments(arguments), createdNodeTypes(createdNodeTypes), - elementHandler(elementHandler) + elementHandler(elementHandler), + supportsAnnotations(supportsAnnotations) { } -ParserState::ParserState(const ParserStateBuilder &builder) - : ParserState(builder.build()) +State::State(const StateBuilder &builder) + : State(builder.build()) { } -/* Class ParserStateBuilder */ +/* Class StateBuilder */ -ParserStateBuilder &ParserStateBuilder::copy(const ParserState &state) +StateBuilder &StateBuilder::copy(const State &state) { this->state = state; return *this; } -ParserStateBuilder &ParserStateBuilder::parent(const ParserState *parent) +StateBuilder &StateBuilder::parent(const State *parent) { - state.parents = ParserStateSet{parent}; + state.parents = StateSet{parent}; return *this; } -ParserStateBuilder &ParserStateBuilder::parents(const ParserStateSet &parents) +StateBuilder &StateBuilder::parents(const StateSet &parents) { state.parents = parents; return *this; } -ParserStateBuilder &ParserStateBuilder::arguments(const Arguments &arguments) +StateBuilder &StateBuilder::arguments(const Arguments &arguments) { state.arguments = arguments; return *this; } -ParserStateBuilder &ParserStateBuilder::createdNodeType(const Rtti *type) +StateBuilder &StateBuilder::createdNodeType(const Rtti *type) { state.createdNodeTypes = RttiSet{type}; return *this; } -ParserStateBuilder &ParserStateBuilder::createdNodeTypes(const RttiSet &types) +StateBuilder &StateBuilder::createdNodeTypes(const RttiSet &types) { state.createdNodeTypes = types; return *this; } -ParserStateBuilder &ParserStateBuilder::elementHandler( +StateBuilder &StateBuilder::elementHandler( HandlerConstructor elementHandler) { state.elementHandler = elementHandler; return *this; } -const ParserState &ParserStateBuilder::build() const { return state; } +StateBuilder &StateBuilder::supportsAnnotations(bool supportsAnnotations) +{ + state.supportsAnnotations = supportsAnnotations; + return *this; +} -/* Class ParserStateDeductor */ +const State &StateBuilder::build() const { return state; } -ParserStateDeductor::ParserStateDeductor( +/* Class StateDeductor */ + +StateDeductor::StateDeductor( std::vector<const Rtti *> signature, - std::vector<const ParserState *> states) + std::vector<const State *> states) : tbl(signature.size()), signature(std::move(signature)), states(std::move(states)) { } -bool ParserStateDeductor::isActive(size_t d, const ParserState *s) +bool StateDeductor::isActive(size_t d, const State *s) { // Lookup the "active" state of (d, s), if it was not already set // (e.second is true) we'll have to calculate it @@ -123,7 +132,7 @@ bool ParserStateDeductor::isActive(size_t d, const ParserState *s) // Check whether any of the parent nodes were active -- either for // the previous element (if this one is generative) or for the // current element (assuming this node was not generative) - for (const ParserState *parent : s->parents) { + for (const State *parent : s->parents) { if ((isGenerative && isActive(d - 1, parent)) || isActive(d, parent)) { res = true; @@ -136,9 +145,9 @@ bool ParserStateDeductor::isActive(size_t d, const ParserState *s) return res; } -std::vector<const ParserState *> ParserStateDeductor::deduce() +std::vector<const State *> StateDeductor::deduce() { - std::vector<const ParserState *> res; + std::vector<const State *> res; if (!signature.empty()) { const size_t D = signature.size(); for (auto s : states) { @@ -153,9 +162,10 @@ std::vector<const ParserState *> ParserStateDeductor::deduce() /* Constant initializations */ -namespace ParserStates { -const ParserState All; -const ParserState None; +namespace States { +const State All; +const State None; +} } } diff --git a/src/core/parser/generic/ParserState.hpp b/src/core/parser/stack/State.hpp index 6487fdd..ea326ec 100644 --- a/src/core/parser/generic/ParserState.hpp +++ b/src/core/parser/stack/State.hpp @@ -17,10 +17,10 @@ */ /** - * @file ParserState.hpp + * @file State.hpp * - * Defines the ParserState class used within the ParserStack pushdown - * automaton and the ParserStateBuilder class for convenient construction of + * Defines the State class used within the ParserStack pushdown + * automaton and the StateBuilder class for convenient construction of * such classes. * * @author Andreas Stöckel (astoecke@techfak.uni-bielefeld.de) @@ -35,10 +35,11 @@ #include <core/common/Argument.hpp> namespace ousia { +namespace parser_stack { // Forward declarations -class ParserStateBuilder; -class ParserState; +class StateBuilder; +class State; class HandlerData; class Handler; using HandlerConstructor = Handler *(*)(const HandlerData &handlerData); @@ -47,17 +48,17 @@ using HandlerConstructor = Handler *(*)(const HandlerData &handlerData); * Set of pointers of parser states -- used for specifying a set of parent * states. */ -using ParserStateSet = std::unordered_set<const ParserState *>; +using StateSet = std::unordered_set<const State *>; /** - * Class used for the complete specification of a ParserState. Stores possible + * Class used for the complete specification of a State. Stores possible * parent states, state handlers and arguments to be passed to that state. */ -struct ParserState { +struct State { /** * Vector containing all possible parent states. */ - ParserStateSet parents; + StateSet parents; /** * Descriptor of the arguments that should be passed to the handler. @@ -66,8 +67,8 @@ struct ParserState { /** * Set containing the types of the nodes that may be created in this - * ParserState. This information is needed for Parsers to reconstruct the - * current ParserState from a given ParserScope when a file is included. + * State. This information is needed for Parsers to reconstruct the + * current State from a given ParserScope when a file is included. */ RttiSet createdNodeTypes; @@ -79,109 +80,119 @@ struct ParserState { HandlerConstructor elementHandler; /** + * Set to true if this handler does support annotations. This is almost + * always false (e.g. all description handlers), except for document + * element handlers. + */ + bool supportsAnnotations; + + /** * Default constructor, initializes the handlers with nullptr. */ - ParserState(); + State(); /** - * Constructor taking values for all fields. Use the ParserStateBuilder - * class for a more convenient construction of ParserState instances. + * Constructor taking values for all fields. Use the StateBuilder + * class for a more convenient construction of State instances. * * @param parents is a vector containing all possible parent states. * @param arguments is a descriptor of arguments that should be passed to * the handler. * @param createdNodeTypes is a set containing the types of the nodes tha - * may be created in this ParserState. This information is needed for - * Parsers to reconstruct the current ParserState from a given ParserScope + * may be created in this State. This information is needed for + * Parsers to reconstruct the current State from a given ParserScope * when a file is included. * @param elementHandler is a pointer at a function which creates a new * concrete Handler instance for the elements described by this state. May * be nullptr in which case no handler instance is created. + * @param supportsAnnotations specifies whether annotations are supported + * here at all. */ - ParserState(ParserStateSet parents, Arguments arguments = Arguments{}, + State(StateSet parents, Arguments arguments = Arguments{}, RttiSet createdNodeTypes = RttiSet{}, - HandlerConstructor elementHandler = nullptr); + HandlerConstructor elementHandler = nullptr, + bool supportsAnnotations = false); /** - * Creates this ParserState from the given ParserStateBuilder instance. + * Creates this State from the given StateBuilder instance. */ - ParserState(const ParserStateBuilder &builder); + State(const StateBuilder &builder); }; /** - * The ParserStateBuilder class is a class used for conveniently building new - * ParserState instances. + * The StateBuilder class is a class used for conveniently building new + * State instances. */ -class ParserStateBuilder { +class StateBuilder { private: /** - * ParserState instance that is currently being built by the - * ParserStateBuilder. + * State instance that is currently being built by the + * StateBuilder. */ - ParserState state; + State state; public: /** - * Copies the ParserState instance and uses it as internal state. Overrides - * all changes made by the ParserStateBuilder. + * Copies the State instance and uses it as internal state. Overrides + * all changes made by the StateBuilder. * * @param state is the state that should be copied. - * @return a reference at this ParserStateBuilder instance for method + * @return a reference at this StateBuilder instance for method * chaining. */ - ParserStateBuilder ©(const ParserState &state); + StateBuilder ©(const State &state); /** * Sets the possible parent states to the single given parent element. * - * @param parent is a pointer at the parent ParserState instance that should + * @param parent is a pointer at the parent State instance that should * be the possible parent state. - * @return a reference at this ParserStateBuilder instance for method + * @return a reference at this StateBuilder instance for method * chaining. */ - ParserStateBuilder &parent(const ParserState *parent); + StateBuilder &parent(const State *parent); /** - * Sets the ParserState instances in the given ParserStateSet as the list of + * Sets the State instances in the given StateSet as the list of * supported parent states. * - * @param parents is a set of pointers at ParserState instances that should + * @param parents is a set of pointers at State instances that should * be the possible parent states. - * @return a reference at this ParserStateBuilder instance for method + * @return a reference at this StateBuilder instance for method * chaining. */ - ParserStateBuilder &parents(const ParserStateSet &parents); + StateBuilder &parents(const StateSet &parents); /** * Sets the arguments that should be passed to the parser state handler to * those given as argument. * * @param arguments is the Arguments instance describing the Arguments that - * should be parsed to a Handler for this ParserState. - * @return a reference at this ParserStateBuilder instance for method + * should be parsed to a Handler for this State. + * @return a reference at this StateBuilder instance for method * chaining. */ - ParserStateBuilder &arguments(const Arguments &arguments); + StateBuilder &arguments(const Arguments &arguments); /** * Sets the Node types this state may produce to the given Rtti descriptor. * * @param type is the Rtti descriptor of the Type that may be produced by * this state. - * @return a reference at this ParserStateBuilder instance for method + * @return a reference at this StateBuilder instance for method * chaining. */ - ParserStateBuilder &createdNodeType(const Rtti *type); + StateBuilder &createdNodeType(const Rtti *type); /** * Sets the Node types this state may produce to the given Rtti descriptors. * * @param types is a set of Rtti descriptors of the Types that may be * produced by this state. - * @return a reference at this ParserStateBuilder instance for method + * @return a reference at this StateBuilder instance for method * chaining. */ - ParserStateBuilder &createdNodeTypes(const RttiSet &types); + StateBuilder &createdNodeTypes(const RttiSet &types); /** * Sets the constructor for the element handler. The constructor creates a @@ -191,31 +202,42 @@ public: * * @param elementHandler is the HandlerConstructor that should create a * new Handler instance. - * @return a reference at this ParserStateBuilder instance for method + * @return a reference at this StateBuilder instance for method * chaining. */ - ParserStateBuilder &elementHandler(HandlerConstructor elementHandler); + StateBuilder &elementHandler(HandlerConstructor elementHandler); /** - * Returns a reference at the internal ParserState instance that was built - * using the ParserStateBuilder. + * Sets the state of the "supportsAnnotations" flags (default value is + * false) * - * @return the built ParserState. + * @param supportsAnnotations should be set to true, if annotations are + * supported for the handlers associated with this document. + * @return a reference at this StateBuilder instance for method + * chaining. */ - const ParserState &build() const; + StateBuilder &supportsAnnotations(bool supportsAnnotations); + + /** + * Returns a reference at the internal State instance that was built + * using the StateBuilder. + * + * @return the built State. + */ + const State &build() const; }; /** - * Class used to deduce the ParserState a Parser is currently in based on the + * Class used to deduce the State a Parser is currently in based on the * types of the Nodes that currently are on the ParserStack. Uses dynamic * programming in order to solve this problem. */ -class ParserStateDeductor { +class StateDeductor { public: /** * Type containing the dynamic programming table. */ - using Table = std::vector<std::unordered_map<const ParserState *, bool>>; + using Table = std::vector<std::unordered_map<const State *, bool>>; private: /** @@ -231,7 +253,7 @@ private: /** * List of states that should be checked for being active. */ - const std::vector<const ParserState *> states; + const std::vector<const State *> states; /** * Used internally to check whether the given parser stack s may have been @@ -239,20 +261,20 @@ private: * * @param d is the signature element. * @param s is the parser state. - * @return true if the the given ParserState may have been active. + * @return true if the the given State may have been active. */ - bool isActive(size_t d, const ParserState *s); + bool isActive(size_t d, const State *s); public: /** - * Constructor of the ParserStateDeductor class. + * Constructor of the StateDeductor class. * * @param signature a Node type signature describing the types of the nodes * which currently reside on e.g. the ParserScope stack. * @param states is a list of states that should be checked. */ - ParserStateDeductor(std::vector<const Rtti *> signature, - std::vector<const ParserState *> states); + StateDeductor(std::vector<const Rtti *> signature, + std::vector<const State *> states); /** * Selects all active states from the given states. Only considers those @@ -260,23 +282,24 @@ public: * * @return a list of states that may actually have been active. */ - std::vector<const ParserState *> deduce(); + std::vector<const State *> deduce(); }; /** - * The ParserStates namespace contains all the global state constants used + * The States namespace contains all the global state constants used * in the ParserStack class. */ -namespace ParserStates { +namespace States { /** * State representing all states. */ -extern const ParserState All; +extern const State All; /** * State representing the initial state. */ -extern const ParserState None; +extern const State None; +} } } diff --git a/test/core/parser/ParserStateTest.cpp b/test/core/parser/ParserStateTest.cpp deleted file mode 100644 index 91d8dcd..0000000 --- a/test/core/parser/ParserStateTest.cpp +++ /dev/null @@ -1,77 +0,0 @@ -/* - Ousía - Copyright (C) 2014, 2015 Benjamin Paaßen, Andreas Stöckel - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - -#include <gtest/gtest.h> - -#include <core/common/Rtti.hpp> -#include <core/parser/ParserState.hpp> - -namespace ousia { - -static const Rtti t1; -static const Rtti t2; -static const Rtti t3; -static const Rtti t4; -static const Rtti t5; - -static const ParserState s1 = ParserStateBuilder().createdNodeType(&t1); -static const ParserState s2a = - ParserStateBuilder().parent(&s1).createdNodeType(&t2); -static const ParserState s2b = - ParserStateBuilder().parent(&s1).createdNodeType(&t2); -static const ParserState s3 = - ParserStateBuilder().parents({&s2a, &s1}).createdNodeType(&t3); -static const ParserState s4 = - ParserStateBuilder().parent(&s3).createdNodeType(&t4); -static const ParserState s5 = - ParserStateBuilder().parent(&s2b).createdNodeType(&t5); - -TEST(ParserStateDeductor, deduce) -{ - using Result = std::vector<const ParserState *>; - using Signature = std::vector<const Rtti *>; - std::vector<const ParserState *> states{&s1, &s2a, &s2b, &s3, &s4, &s5}; - - // Should not crash on empty signature - ASSERT_EQ(Result{}, ParserStateDeductor(Signature{}, states).deduce()); - - // Try repeating signature elements - ASSERT_EQ(Result({&s1}), - ParserStateDeductor(Signature({&t1}), states).deduce()); - ASSERT_EQ(Result({&s1}), - ParserStateDeductor(Signature({&t1, &t1}), states).deduce()); - ASSERT_EQ(Result({&s1}), - ParserStateDeductor(Signature({&t1, &t1, &t1}), states).deduce()); - - // Go to another state - ASSERT_EQ(Result({&s2a, &s2b}), - ParserStateDeductor(Signature({&t1, &t1, &t2}), states).deduce()); - ASSERT_EQ(Result({&s4}), - ParserStateDeductor(Signature({&t1, &t3, &t4}), states).deduce()); - - // Skip one state - ASSERT_EQ(Result({&s4}), - ParserStateDeductor(Signature({&t2, &t4}), states).deduce()); - - // Impossible signature - ASSERT_EQ(Result({}), - ParserStateDeductor(Signature({&t4, &t5}), states).deduce()); - -} -} - diff --git a/test/core/parser/stack/StateTest.cpp b/test/core/parser/stack/StateTest.cpp new file mode 100644 index 0000000..e503d30 --- /dev/null +++ b/test/core/parser/stack/StateTest.cpp @@ -0,0 +1,79 @@ +/* + Ousía + Copyright (C) 2014, 2015 Benjamin Paaßen, Andreas Stöckel + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include <gtest/gtest.h> + +#include <core/common/Rtti.hpp> +#include <core/parser/stack/State.hpp> + +namespace ousia { +namespace parser_stack { + +static const Rtti t1; +static const Rtti t2; +static const Rtti t3; +static const Rtti t4; +static const Rtti t5; + +static const State s1 = StateBuilder().createdNodeType(&t1); +static const State s2a = + StateBuilder().parent(&s1).createdNodeType(&t2); +static const State s2b = + StateBuilder().parent(&s1).createdNodeType(&t2); +static const State s3 = + StateBuilder().parents({&s2a, &s1}).createdNodeType(&t3); +static const State s4 = + StateBuilder().parent(&s3).createdNodeType(&t4); +static const State s5 = + StateBuilder().parent(&s2b).createdNodeType(&t5); + +TEST(StateDeductor, deduce) +{ + using Result = std::vector<const State *>; + using Signature = std::vector<const Rtti *>; + std::vector<const State *> states{&s1, &s2a, &s2b, &s3, &s4, &s5}; + + // Should not crash on empty signature + ASSERT_EQ(Result{}, StateDeductor(Signature{}, states).deduce()); + + // Try repeating signature elements + ASSERT_EQ(Result({&s1}), + StateDeductor(Signature({&t1}), states).deduce()); + ASSERT_EQ(Result({&s1}), + StateDeductor(Signature({&t1, &t1}), states).deduce()); + ASSERT_EQ(Result({&s1}), + StateDeductor(Signature({&t1, &t1, &t1}), states).deduce()); + + // Go to another state + ASSERT_EQ(Result({&s2a, &s2b}), + StateDeductor(Signature({&t1, &t1, &t2}), states).deduce()); + ASSERT_EQ(Result({&s4}), + StateDeductor(Signature({&t1, &t3, &t4}), states).deduce()); + + // Skip one state + ASSERT_EQ(Result({&s4}), + StateDeductor(Signature({&t2, &t4}), states).deduce()); + + // Impossible signature + ASSERT_EQ(Result({}), + StateDeductor(Signature({&t4, &t5}), states).deduce()); + +} +} +} + |