From 6decad0b8e7e369bd8215f31a45dd3eae982d2a9 Mon Sep 17 00:00:00 2001 From: Andreas Stöckel Date: Wed, 21 Jan 2015 01:17:49 +0100 Subject: 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 --- src/core/parser/ParserScope.cpp | 162 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 162 insertions(+) create mode 100644 src/core/parser/ParserScope.cpp (limited to 'src/core/parser/ParserScope.cpp') diff --git a/src/core/parser/ParserScope.cpp b/src/core/parser/ParserScope.cpp new file mode 100644 index 0000000..b236a1f --- /dev/null +++ b/src/core/parser/ParserScope.cpp @@ -0,0 +1,162 @@ +/* + 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 "ParserScope.hpp" + +namespace ousia { + +/* Class ParserScopeBase */ + +Rooted ParserScopeBase::resolve(const std::vector &path, + const Rtti &type, Logger &logger) +{ + // Go up the stack and try to resolve the + for (auto it = nodes.rbegin(); it != nodes.rend(); it++) { + std::vector res = (*it)->resolve(path, type); + + // Abort if the object could not be resolved + if (res.empty()) { + continue; + } + + // Log an error if the object is not unique + if (res.size() > 1) { + logger.error(std::string("The reference \"") + + Utils::join(path, ".") + ("\" is ambigous!")); + logger.note("Referenced objects are:"); + for (const ResolutionResult &r : res) { + logger.note(Utils::join(r.path(), ".")); + } + } + return res[0].node; + } + return nullptr; +} + +/* Class DeferredResolution */ + +DeferredResolution::DeferredResolution(const NodeVector &nodes, + const std::vector &path, + const Rtti &type, + ResolutionResultCallback resultCallback, + const SourceLocation &location) + : scope(nodes), + resultCallback(resultCallback), + path(path), + type(type), + location(location) +{ +} + +bool DeferredResolution::resolve(Logger &logger) +{ + Rooted res = scope.resolve(path, type, logger); + if (res != nullptr) { + try { + resultCallback(res, logger); + } + catch (LoggableException ex) { + logger.log(ex); + } + return true; + } + return false; +} + +/* Class ParserScope */ + +void ParserScope::push(Handle node) { nodes.push_back(node); } + +void ParserScope::pop() { nodes.pop_back(); } + +Rooted ParserScope::getRoot() const { return nodes.front(); } + +Rooted ParserScope::getLeaf() { return nodes.back(); } + +bool ParserScope::resolve(const std::vector &path, const Rtti &type, + Logger &logger, ResolutionImposterCallback imposterCallback, + ResolutionResultCallback resultCallback, + const SourceLocation &location) +{ + if (!resolve(path, type, logger, resultCallback, location)) { + resultCallback(imposterCallback(), logger); + return false; + } + return true; +} + +bool ParserScope::resolve(const std::vector &path, const Rtti &type, + Logger &logger, ResolutionResultCallback resultCallback, + const SourceLocation &location) +{ + Rooted res = ParserScopeBase::resolve(path, type, logger); + if (res != nullptr) { + try { + resultCallback(res, logger); + } + catch (LoggableException ex) { + logger.log(ex, location); + } + return true; + } + deferred.emplace_back(nodes, path, type, resultCallback, location); + return false; +} + +bool ParserScope::performDeferredResolution(Logger &logger) +{ + // Repeat the resolution process as long as something has changed in the + // last iteration (resolving a node may cause other nodes to be resolvable). + while (true) { + // Iterate over all deferred resolution processes, + bool hasChange = false; + for (auto it = deferred.begin(); it != deferred.end();) { + if (it->resolve(logger)) { + it = deferred.erase(it); + hasChange = true; + } else { + it++; + } + } + + // Abort if nothing has changed in the last iteration + if (!hasChange) { + break; + } + } + + // We were successful if there are no more deferred resolutions + if (deferred.empty()) { + return true; + } + + // Output error messages for all elements for which resolution did not + // succeed. + for (const auto &failed : deferred) { + logger.error(std::string("Could not resolve ") + failed.type.name + + std::string(" \"") + Utils::join(failed.path, ".") + + std::string("\""), + failed.location); + } + deferred.clear(); + return false; +} +} + -- cgit v1.2.3