diff options
author | Andreas Stöckel <astoecke@techfak.uni-bielefeld.de> | 2015-01-21 01:17:49 +0100 |
---|---|---|
committer | Andreas Stöckel <astoecke@techfak.uni-bielefeld.de> | 2015-01-21 01:17:49 +0100 |
commit | 6decad0b8e7e369bd8215f31a45dd3eae982d2a9 (patch) | |
tree | 96d22db47629956c554d11a9e56bc68a2fc9b40b /src/core/parser/ParserScope.hpp | |
parent | 311a770805dff2cdffc1ecbfbbf0c5aae44c8878 (diff) |
Some further refactoring -- renamed Scope to ParserScope, got rid of parser namespace, added new functionality to RegistryClass, wrote documentation, added function for extracting file extensions to Utils
Diffstat (limited to 'src/core/parser/ParserScope.hpp')
-rw-r--r-- | src/core/parser/ParserScope.hpp | 427 |
1 files changed, 427 insertions, 0 deletions
diff --git a/src/core/parser/ParserScope.hpp b/src/core/parser/ParserScope.hpp new file mode 100644 index 0000000..a759738 --- /dev/null +++ b/src/core/parser/ParserScope.hpp @@ -0,0 +1,427 @@ +/* + 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/>. +*/ + +#ifndef _OUSIA_PARSER_SCOPE_HPP_ +#define _OUSIA_PARSER_SCOPE_HPP_ + +#include <functional> +#include <list> +#include <vector> + +#include <core/common/Logger.hpp> +#include <core/common/Rtti.hpp> +#include <core/common/Utils.hpp> +#include <core/model/Node.hpp> + +/** + * @file ParserScope.hpp + * + * Contains the ParserScope class used for resolving references based on the current + * parser state. + * + * @author Andreas Stöckel (astoecke@techfak.uni-bielefeld.de) + */ + +namespace ousia { + +// Forward declaration +class CharReader; +class Registry; +class Logger; +class ParserScope; + +/** + * Callback function type used for creating a dummy object while no correct + * object is available for resolution. + */ +using ResolutionImposterCallback = std::function<Rooted<Node>()>; + +/** + * Callback function type called whenever the result of a resolution is + * available. + */ +using ResolutionResultCallback = + std::function<void(Handle<Node>, Logger &logger)>; + +/** + * Base class for the + */ +class ParserScopeBase { +protected: + /** + * List containing all nodes currently on the scope, with the newest nodes + * being pushed to the back of the list. + */ + NodeVector<Node> nodes; + +public: + /** + * Default constructor, creates an empty ParserScope instance. + */ + ParserScopeBase() {} + + /** + * Creates a new instance of the ParserScopeBase class, copying the the given + * nodes as initial start value of the node stack. This could for example + * be initialized with the path of a node. + * + * @param nodes is a node vector containing the current node stack. + */ + ParserScopeBase(const NodeVector<Node> &nodes) : nodes(nodes) {} + + /** + * Tries to resolve a node for the given type and path for all nodes that + * are currently in the stack, starting with the topmost node on the stack. + * + * @param path is the path for which a node should be resolved. + * @param type is the type of the node that should be resolved. + * @param logger is the logger instance into which resolution problems + * should be logged. + * @return a reference at a resolved node or nullptr if no node could be + * found. + */ + Rooted<Node> resolve(const std::vector<std::string> &path, + const Rtti &type, Logger &logger); +}; + +/** + * Class used for representing a deferred resolution. A deferred resolution is + * triggered whenever an object cannot be resolved, but there may be a chance + * that it can be resolved in the future. This happens e.g. if a document is + * just being parsed and the object that is being refered to has not been + * reached yet. + */ +class DeferredResolution { +private: + /** + * Copy of the scope at the time when the resolution was first triggered. + */ + ParserScopeBase scope; + + /** + * Callback function to be called when an element is successfully resolved. + */ + ResolutionResultCallback resultCallback; + +public: + /** + * Path queried for the resolution. + */ + std::vector<std::string> path; + + /** + * Reference at the type of the object that should be resolved. + */ + const Rtti &type; + + /** + * Position at which the resolution was triggered. + */ + const SourceLocation location; + + /** + * Constructor of the DeferredResolutionScope class. Copies the given + * arguments. + * + * @param nodes is a reference at the current internal node stack of the + * ParserScope class. + * @param path is the path that was queried when the resolution failed the + * first time. + * @param type is the Rtti of the element that should be queried. + * @param resultCallback is the callback function that should be called if + * the desired element has indeed been found. + * @param location is the location at which the resolution was triggered. + */ + DeferredResolution(const NodeVector<Node> &nodes, + const std::vector<std::string> &path, + const Rtti &type, + ResolutionResultCallback resultCallback, + const SourceLocation &location = SourceLocation{}); + + /** + * Performs the actual deferred resolution and calls the resultCallback + * callback function in case the resolution is sucessful. In this case + * returns true, false otherwise. + * + * @param logger is the logger instance to which error messages should be + * logged. + * @return true if the resolution was successful, false otherwise. + */ + bool resolve(Logger &logger); +}; + +/** + * Provides an interface for document parsers to resolve references based on the + * current position in the created document tree. The ParserScope class itself + * is represented as a chain of ParserScope objects where each element has a + * reference to a Node object attached to it. + */ +class ParserScope : public ParserScopeBase { +private: + /** + * List containing all deferred resolution descriptors. + */ + std::list<DeferredResolution> deferred; + +public: + /** + * Default constructor of the ParserScope class, creates an empty ParserScope with no + * element on the internal stack. + */ + ParserScope() {} + + /** + * Pushes a new node onto the scope. + * + * @param node is the node that should be used for local lookup. + */ + void push(Handle<Node> node); + + /** + * Removes the last pushed node from the scope. + */ + void pop(); + + /** + * Returns the top-most Node instance in the ParserScope hirarchy. + * + * @return a reference at the root node. + */ + Rooted<Node> getRoot() const; + + /** + * Returns the bottom-most Node instance in the ParserScope hirarchy, e.g. the + * node that was pushed last onto the stack. + * + * @return a reference at the leaf node. + */ + Rooted<Node> getLeaf(); + + /** + * Tries to resolve a node for the given type and path for all nodes + * currently on the stack, starting with the topmost node on the stack. + * Calls the "imposterCallback" function for obtaining a temporary result if + * a node cannot be resolved right now. The "resultCallback" is at most + * called twice: Once when this method is called (probably with the + * temporary) and another time if the resolution turned out to be successful + * at a later point in time. + * + * @param path is the path for which a node should be resolved. + * @param type is the type of the node that should be resolved. + * @param logger is the logger instance into which resolution problems + * should be logged. + * @param imposterCallback is the callback function that is called if + * the node cannot be resolved at this moment. It gives the caller the + * possibility to create an imposter (a temporary object) that may be used + * later in the resolution process. + * @param resultCallback is the callback function to which the result of + * the resolution process is passed. This function is called at least once + * either with the imposter (if the resolution was not successful) or the + * resolved object directly when this function is called. If the resolution + * was not successful the first time, it may be called another time later + * in the context of the "performDeferredResolution" function. + * @param location is the location in the current source file in which the + * resolution was triggered. + * @return true if the resolution was immediately successful. This does not + * mean, that the resolved object does not exist, as it may be resolved + * later. + */ + bool resolve(const std::vector<std::string> &path, const Rtti &type, + Logger &logger, ResolutionImposterCallback imposterCallback, + ResolutionResultCallback resultCallback, + const SourceLocation &location = SourceLocation{}); + + /** + * Tries to resolve a node for the given type and path for all nodes + * currently on the stack, starting with the topmost node on the stack. + * The "resultCallback" is called when the resolution was successful, which + * may be at a later point in time. + * + * @param path is the path for which a node should be resolved. + * @param type is the type of the node that should be resolved. + * @param logger is the logger instance into which resolution problems + * should be logged. + * @param resultCallback is the callback function to which the result of + * the resolution process is passed. This function is called once the + * resolution was successful. + * @param location is the location in the current source file in which the + * resolution was triggered. + * @return true if the resolution was immediately successful. This does not + * mean, that the resolved object does not exist, as it may be resolved + * later. + */ + bool resolve(const std::vector<std::string> &path, const Rtti &type, + Logger &logger, ResolutionResultCallback resultCallback, + const SourceLocation &location = SourceLocation{}); + + /** + * Tries to resolve a node for the given type and path for all nodes + * currently on the stack, starting with the topmost node on the stack. + * Calls the "imposterCallback" function for obtaining a temporary result if + * a node cannot be resolved right now. The "resultCallback" is at most + * called twice: Once when this method is called (probably with the + * temporary) and another time if the resolution turned out to because + * successful at a later point in time. + * + * @tparam T is the type of the node that should be resolved. + * @param path is the path for which a node should be resolved. + * @param logger is the logger instance into which resolution problems + * should be logged. + * @param imposterCallback is the callback function that is called if + * the node cannot be resolved at this moment. It gives the caller the + * possibility to create an imposter (a temporary object) that may be used + * later in the resolution process. + * @param resultCallback is the callback function to which the result of + * the resolution process is passed. This function is called at least once + * either with the imposter (if the resolution was not successful) or the + * resolved object directly when this function is called. If the resolution + * was not successful the first time, it may be called another time later + * in the context of the "performDeferredResolution" function. + * @param location is the location in the current source file in which the + * resolution was triggered. + * @return true if the resolution was immediately successful. This does not + * mean, that the resolved object does not exist, as it may be resolved + * later. + */ + template <class T> + bool resolve(const std::vector<std::string> &path, Logger &logger, + std::function<Rooted<T>()> imposterCallback, + std::function<void(Handle<T>, Logger &)> resultCallback, + const SourceLocation &location = SourceLocation{}) + { + return resolve( + path, typeOf<T>(), logger, + [imposterCallback]() -> Rooted<Node> { return imposterCallback(); }, + [resultCallback](Handle<Node> node, Logger &logger) { + resultCallback(node.cast<T>(), logger); + }, + location); + } + + /** + * Tries to resolve a node for the given type and path for all nodes + * currently on the stack, starting with the topmost node on the stack. + * The "resultCallback" is called when the resolution was successful, which + * may be at a later point in time. + * + * @tparam T is the type of the node that should be resolved. + * @param path is the path for which a node should be resolved. + * @param logger is the logger instance into which resolution problems + * should be logged. + * @param resultCallback is the callback function to which the result of + * the resolution process is passed. This function is called once the + * resolution was successful. + * @param location is the location in the current source file in which the + * resolution was triggered. + * @return true if the resolution was immediately successful. This does not + * mean, that the resolved object does not exist, as it may be resolved + * later. + */ + template <class T> + bool resolve(const std::vector<std::string> &path, Logger &logger, + std::function<void(Handle<T>, Logger &)> resultCallback, + const SourceLocation &location = SourceLocation{}) + { + return resolve(path, typeOf<T>(), logger, + [resultCallback](Handle<Node> node, Logger &logger) { + resultCallback(node.cast<T>(), logger); + }, + location); + } + + /** + * Tries to resolve a node for the given type and path for all nodes + * currently on the stack, starting with the topmost node on the stack. + * Calls the "imposterCallback" function for obtaining a temporary result if + * a node cannot be resolved right now. The "resultCallback" is at most + * called twice: Once when this method is called (probably with the + * temporary) and another time if the resolution turned out to because + * successful at a later point in time. + * + * @tparam T is the type of the node that should be resolved. + * @param name is the path for which a node should be resolved. The name is + * split at '.' to form a path. + * @param logger is the logger instance into which resolution problems + * should be logged. + * @param imposterCallback is the callback function that is called if + * the node cannot be resolved at this moment. It gives the caller the + * possibility to create an imposter (a temporary object) that may be used + * later in the resolution process. + * @param resultCallback is the callback function to which the result of + * the resolution process is passed. This function is called at least once + * either with the imposter (if the resolution was not successful) or the + * resolved object directly when this function is called. If the resolution + * was not successful the first time, it may be called another time later + * in the context of the "performDeferredResolution" function. + * @param location is the location in the current source file in which the + * resolution was triggered. + * @return true if the resolution was immediately successful. This does not + * mean, that the resolved object does not exist, as it may be resolved + * later. + */ + template <class T> + bool resolve(const std::string &name, Logger &logger, + std::function<Rooted<T>()> imposterCallback, + std::function<void(Handle<T>, Logger &)> resultCallback, + const SourceLocation &location = SourceLocation{}) + { + return resolve<T>(Utils::split(name, '.'), logger, imposterCallback, + resultCallback, location); + } + + /** + * Tries to resolve a node for the given type and path for all nodes + * currently on the stack, starting with the topmost node on the stack. + * The "resultCallback" is called when the resolution was successful, which + * may be at a later point in time. + * + * @tparam T is the type of the node that should be resolved. + * @param name is the path for which a node should be resolved. The name is + * split at '.' to form a path. + * @param logger is the logger instance into which resolution problems + * should be logged. + * @param resultCallback is the callback function to which the result of + * the resolution process is passed. This function is called once the + * resolution was successful. + * @param location is the location in the current source file in which the + * resolution was triggered. + * @return true if the resolution was immediately successful. This does not + * mean, that the resolved object does not exist, as it may be resolved + * later. + */ + template <class T> + bool resolve(const std::string &name, Logger &logger, + std::function<void(Handle<T>, Logger &)> resultCallback, + const SourceLocation &location = SourceLocation{}) + { + return resolve<T>(Utils::split(name, '.'), logger, resultCallback, + location); + } + + /** + * Tries to resolve all currently deferred resolution steps. The list of + * pending deferred resolutions is cleared after this function has run. + * + * @param logger is the logger instance into which errors should be logged. + */ + bool performDeferredResolution(Logger &logger); +}; +} + +#endif /* _OUSIA_PARSER_SCOPE_HPP_ */ + |