diff options
author | Andreas Stöckel <astoecke@techfak.uni-bielefeld.de> | 2015-01-16 17:02:04 +0100 |
---|---|---|
committer | Andreas Stöckel <andreas@somweyr.de> | 2015-01-16 17:02:04 +0100 |
commit | 378ff2235fdf32983ebf2186a9127e51cbe8a0ab (patch) | |
tree | 12223877b7631dc2adc9d9d69cd7e31da079e27e /src/core/parser/Scope.cpp | |
parent | 6c1288bd3746329c3721c6aca1fb0420061831c3 (diff) |
Allowing deferred resolution of Nodes
Diffstat (limited to 'src/core/parser/Scope.cpp')
-rw-r--r-- | src/core/parser/Scope.cpp | 129 |
1 files changed, 127 insertions, 2 deletions
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<Node> Scope::resolve(const std::vector<std::string> &path, - const RttiType &type, Logger &logger) +/* Class GuardedScope */ + +GuardedScope::GuardedScope(Scope *scope, Handle<Node> 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<Node> ScopeBase::resolve(const std::vector<std::string> &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<Node> Scope::resolve(const std::vector<std::string> &path, } return nullptr; } + +/* Class DeferredResolution */ + +DeferredResolution::DeferredResolution( + const NodeVector<Node> &nodes, const std::vector<std::string> &path, + const RttiType &type, std::function<void(Handle<Node>)> resultCallback) + : scope(nodes), resultCallback(resultCallback), path(path), type(type) +{ +} + +bool DeferredResolution::resolve(Logger &logger) +{ + Rooted<Node> res = scope.resolve(path, type, logger); + if (res != nullptr) { + resultCallback(res); + return true; + } + return false; +} + +/* Class Scope */ + +void Scope::push(Handle<Node> node) { nodes.push_back(node); } + +void Scope::pop() { nodes.pop_back(); } + +GuardedScope Scope::descend(Handle<Node> node) +{ + return GuardedScope{this, node}; +} + +Rooted<Node> Scope::getRoot() const { return nodes.front(); } + +Rooted<Node> Scope::getLeaf() { return nodes.back(); } + +bool Scope::resolve(const std::vector<std::string> &path, const RttiType &type, + Logger &logger, + std::function<Rooted<Node>()> imposterCallback, + std::function<void(Handle<Node>)> resultCallback) +{ + Rooted<Node> 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<std::string> &path, const RttiType &type, + Logger &logger, + std::function<void(Handle<Node>)> successCallback) +{ + Rooted<Node> 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(); } } } |