summaryrefslogtreecommitdiff
path: root/src/core/parser/ParserScope.cpp
diff options
context:
space:
mode:
authorAndreas Stöckel <astoecke@techfak.uni-bielefeld.de>2015-01-21 01:17:49 +0100
committerAndreas Stöckel <astoecke@techfak.uni-bielefeld.de>2015-01-21 01:17:49 +0100
commit6decad0b8e7e369bd8215f31a45dd3eae982d2a9 (patch)
tree96d22db47629956c554d11a9e56bc68a2fc9b40b /src/core/parser/ParserScope.cpp
parent311a770805dff2cdffc1ecbfbbf0c5aae44c8878 (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.cpp')
-rw-r--r--src/core/parser/ParserScope.cpp162
1 files changed, 162 insertions, 0 deletions
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 <http://www.gnu.org/licenses/>.
+*/
+
+#include <core/common/Utils.hpp>
+
+#include "ParserScope.hpp"
+
+namespace ousia {
+
+/* Class ParserScopeBase */
+
+Rooted<Node> ParserScopeBase::resolve(const std::vector<std::string> &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<ResolutionResult> 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<Node> &nodes,
+ const std::vector<std::string> &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<Node> 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> node) { nodes.push_back(node); }
+
+void ParserScope::pop() { nodes.pop_back(); }
+
+Rooted<Node> ParserScope::getRoot() const { return nodes.front(); }
+
+Rooted<Node> ParserScope::getLeaf() { return nodes.back(); }
+
+bool ParserScope::resolve(const std::vector<std::string> &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<std::string> &path, const Rtti &type,
+ Logger &logger, ResolutionResultCallback resultCallback,
+ const SourceLocation &location)
+{
+ Rooted<Node> 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;
+}
+}
+