From 378ff2235fdf32983ebf2186a9127e51cbe8a0ab Mon Sep 17 00:00:00 2001 From: Andreas Stöckel Date: Fri, 16 Jan 2015 17:02:04 +0100 Subject: Allowing deferred resolution of Nodes --- src/core/parser/Scope.cpp | 129 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 127 insertions(+), 2 deletions(-) (limited to 'src/core/parser/Scope.cpp') diff --git a/src/core/parser/Scope.cpp b/src/core/parser/Scope.cpp index c73b908..d76af9c 100644 --- a/src/core/parser/Scope.cpp +++ b/src/core/parser/Scope.cpp @@ -23,8 +23,30 @@ namespace ousia { namespace parser { -Rooted Scope::resolve(const std::vector &path, - const RttiType &type, Logger &logger) +/* Class GuardedScope */ + +GuardedScope::GuardedScope(Scope *scope, Handle node) : scope(scope) +{ + scope->push(node); +} + +GuardedScope::~GuardedScope() +{ + if (scope) { + scope->pop(); + } +} + +GuardedScope::GuardedScope(GuardedScope &&s) +{ + scope = s.scope; + s.scope = nullptr; +} + +/* Class ScopeBase */ + +Rooted ScopeBase::resolve(const std::vector &path, + const RttiType &type, Logger &logger) { // Go up the stack and try to resolve the for (auto it = nodes.rbegin(); it != nodes.rend(); it++) { @@ -48,5 +70,108 @@ Rooted Scope::resolve(const std::vector &path, } return nullptr; } + +/* Class DeferredResolution */ + +DeferredResolution::DeferredResolution( + const NodeVector &nodes, const std::vector &path, + const RttiType &type, std::function)> resultCallback) + : scope(nodes), resultCallback(resultCallback), path(path), type(type) +{ +} + +bool DeferredResolution::resolve(Logger &logger) +{ + Rooted res = scope.resolve(path, type, logger); + if (res != nullptr) { + resultCallback(res); + return true; + } + return false; +} + +/* Class Scope */ + +void Scope::push(Handle node) { nodes.push_back(node); } + +void Scope::pop() { nodes.pop_back(); } + +GuardedScope Scope::descend(Handle node) +{ + return GuardedScope{this, node}; +} + +Rooted Scope::getRoot() const { return nodes.front(); } + +Rooted Scope::getLeaf() { return nodes.back(); } + +bool Scope::resolve(const std::vector &path, const RttiType &type, + Logger &logger, + std::function()> imposterCallback, + std::function)> resultCallback) +{ + Rooted res = ScopeBase::resolve(path, type, logger); + if (res != nullptr) { + resultCallback(res); + return true; + } + resultCallback(imposterCallback()); + deferred.emplace_back(nodes, path, type, resultCallback); + return false; +} + +bool Scope::resolve(const std::vector &path, const RttiType &type, + Logger &logger, + std::function)> successCallback) +{ + Rooted res = ScopeBase::resolve(path, type, logger); + if (res != nullptr) { + successCallback(res); + return true; + } + deferred.emplace_back(nodes, path, type, successCallback); + return false; +} + +bool Scope::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; + } + } + + // Output an error message if there are still deferred elements left that + // could not be resolved + // TODO: Log this at the position at which the resolution was originally + // triggered + if (!deferred.empty()) { + for (const auto &failed : deferred) { + logger.error( + std::string("Could not resolve \"") + + Utils::join(failed.path, ".") + + std::string("\" of internal type " + failed.type.name)); + } + } + + // We were successful if there are no more deferred resolutions + return deferred.empty(); +} + +void Scope::purgeDeferredResolutions() { deferred.clear(); } } } -- cgit v1.2.3