summaryrefslogtreecommitdiff
path: root/src/core/parser
diff options
context:
space:
mode:
authorBenjamin Paassen <bpaassen@techfak.uni-bielefeld.de>2015-01-30 10:41:39 +0100
committerBenjamin Paassen <bpaassen@techfak.uni-bielefeld.de>2015-01-30 10:41:39 +0100
commit33628e1f35ab1eb593391e87faaf9115b203c9b3 (patch)
tree2ea052b03f74cad35129c79d3cd5c09c0b969337 /src/core/parser
parentd6d7d7f2858d33bb3bcd950aa866b9a09047082f (diff)
parentc4da68ba28e742810d05d35f0a26ef1d9b8c5b6c (diff)
Merge branch 'master' of somweyr.de:ousia
Diffstat (limited to 'src/core/parser')
-rw-r--r--src/core/parser/ParserScope.cpp192
-rw-r--r--src/core/parser/ParserScope.hpp196
2 files changed, 319 insertions, 69 deletions
diff --git a/src/core/parser/ParserScope.cpp b/src/core/parser/ParserScope.cpp
index 0de0dbf..c7a9f2a 100644
--- a/src/core/parser/ParserScope.cpp
+++ b/src/core/parser/ParserScope.cpp
@@ -18,6 +18,7 @@
#include <core/common/Exceptions.hpp>
#include <core/common/Utils.hpp>
+#include <core/model/Typesystem.hpp>
#include "ParserScope.hpp"
@@ -31,12 +32,13 @@ ParserScopeBase::ParserScopeBase(const NodeVector<Node> &nodes) : nodes(nodes)
{
}
-Rooted<Node> ParserScopeBase::resolve(const std::vector<std::string> &path,
- const Rtti &type, Logger &logger)
+Rooted<Node> ParserScopeBase::resolve(const Rtti &type,
+ const std::vector<std::string> &path,
+ 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);
+ std::vector<ResolutionResult> res = (*it)->resolve(type, path);
// Abort if the object could not be resolved
if (res.empty()) {
@@ -79,14 +81,14 @@ bool DeferredResolution::resolve(
// Fork the logger to prevent error messages from being shown if we actively
// ignore the resolution result
LoggerFork loggerFork = logger.fork();
- Rooted<Node> res = scope.resolve(path, type, loggerFork);
+ Rooted<Node> res = scope.resolve(type, path, loggerFork);
if (res != nullptr) {
if (!ignore.count(res.get())) {
loggerFork.commit();
try {
// Push the location onto the logger default location stack
GuardedLogger loggerGuard(logger, *owner);
- resultCallback(res, logger);
+ resultCallback(res, owner, logger);
}
catch (LoggableException ex) {
logger.log(ex);
@@ -99,6 +101,16 @@ bool DeferredResolution::resolve(
return false;
}
+void DeferredResolution::fail(Logger &logger)
+{
+ try {
+ resultCallback(nullptr, owner, logger);
+ }
+ catch (LoggableException ex) {
+ logger.log(ex);
+ }
+}
+
/* Class ParserScope */
ParserScope::ParserScope(const NodeVector<Node> &nodes,
@@ -227,29 +239,29 @@ bool ParserScope::getFlag(ParserFlag flag)
return false;
}
-bool ParserScope::resolve(const std::vector<std::string> &path,
- const Rtti &type, Logger &logger,
+bool ParserScope::resolve(const Rtti &type,
+ const std::vector<std::string> &path,
+ Handle<Node> owner, Logger &logger,
ResolutionImposterCallback imposterCallback,
- ResolutionResultCallback resultCallback,
- Handle<Node> owner)
+ ResolutionResultCallback resultCallback)
{
- if (!resolve(path, type, logger, resultCallback, owner)) {
- resultCallback(imposterCallback(), logger);
+ if (!resolve(type, path, owner, logger, resultCallback)) {
+ resultCallback(imposterCallback(), owner, logger);
return false;
}
return true;
}
-bool ParserScope::resolve(const std::vector<std::string> &path,
- const Rtti &type, Logger &logger,
- ResolutionResultCallback resultCallback,
- Handle<Node> owner)
+bool ParserScope::resolve(const Rtti &type,
+ const std::vector<std::string> &path,
+ Handle<Node> owner, Logger &logger,
+ ResolutionResultCallback resultCallback)
{
// Try to directly resolve the node
- Rooted<Node> res = ParserScopeBase::resolve(path, type, logger);
+ Rooted<Node> res = ParserScopeBase::resolve(type, path, logger);
if (res != nullptr && !awaitingResolution.count(res.get())) {
try {
- resultCallback(res, logger);
+ resultCallback(res, owner, logger);
}
catch (LoggableException ex) {
logger.log(ex, *owner);
@@ -266,6 +278,149 @@ bool ParserScope::resolve(const std::vector<std::string> &path,
return false;
}
+bool ParserScope::resolveType(const std::vector<std::string> &path,
+ Handle<Node> owner, Logger &logger,
+ ResolutionResultCallback resultCallback)
+{
+ // Check whether the given path denotes an array, if yes recursively resolve
+ // the inner type and wrap it in an array type (this allows multi
+ // dimensional arrays).
+ if (!path.empty()) {
+ const std::string &last = path.back();
+ if (last.size() >= 2 && last.substr(last.size() - 2, 2) == "[]") {
+ // Type ends with "[]", remove this from the last element in the
+ // list
+ std::vector<std::string> p = path;
+ p.back() = p.back().substr(0, last.size() - 2);
+
+ // Resolve the rest of the type
+ return resolveType(p, owner, logger,
+ [resultCallback](Handle<Node> resolved,
+ Handle<Node> owner,
+ Logger &logger) {
+ if (resolved != nullptr) {
+ Rooted<ArrayType> arr{new ArrayType{resolved.cast<Type>()}};
+ resultCallback(arr, owner, logger);
+ } else {
+ resultCallback(nullptr, owner, logger);
+ }
+ });
+ }
+ }
+
+ // Requested type is not an array, call the usual resolve function
+ return resolve(RttiTypes::Type, path, owner, logger, resultCallback);
+}
+
+bool ParserScope::resolveType(const std::string &name, Handle<Node> owner,
+ Logger &logger,
+ ResolutionResultCallback resultCallback)
+{
+ return resolveType(Utils::split(name, '.'), owner, logger, resultCallback);
+}
+
+bool ParserScope::resolveTypeWithValue(const std::vector<std::string> &path,
+ Handle<Node> owner, Variant &value,
+ Logger &logger,
+ ResolutionResultCallback resultCallback)
+{
+ // Fork the parser scope -- constants need to be resolved in the same
+ // context as this resolve call
+ std::shared_ptr<ParserScope> scope = std::make_shared<ParserScope>(fork());
+
+ return resolveType(
+ path, owner, logger,
+ [=](Handle<Node> resolved, Handle<Node> owner, Logger &logger) mutable {
+ // Abort if the lookup failed
+ if (resolved == nullptr) {
+ resultCallback(resolved, owner, logger);
+ return;
+ }
+
+ // Fetch the type reference and the manager reference
+ Rooted<Type> type = resolved.cast<Type>();
+ Manager *mgr = &type->getManager();
+
+ // The type has been resolved, try to resolve magic values as
+ // constants and postpone calling the callback function until
+ // all magic values have been resolved
+ std::shared_ptr<bool> isAsync = std::make_shared<bool>(false);
+ std::shared_ptr<int> magicCount = std::make_shared<int>(0);
+ type->build(value, logger, [=](Variant &magicValue, bool isValid,
+ ManagedUid innerTypeUid) mutable {
+ // Fetch the inner type
+ Rooted<Type> innerType =
+ dynamic_cast<Type *>(mgr->getManaged(innerTypeUid));
+ if (innerType == nullptr) {
+ return;
+ }
+
+ // Fetch a pointer at the variant
+ Variant *magicValuePtr = &magicValue;
+
+ // Increment the number of encountered magic values
+ (*magicCount)++;
+
+ // Try to resolve the value as constant
+ std::string constantName = magicValue.asMagic();
+ scope->resolve<Constant>(constantName, owner, logger,
+ [=](Handle<Node> resolved,
+ Handle<Node> owner,
+ Logger &logger) mutable {
+ if (resolved != nullptr) {
+ // Make sure the constant is of the correct inner type
+ Rooted<Constant> constant = resolved.cast<Constant>();
+ Rooted<Type> constantType = constant->getType();
+ if (constantType != innerType) {
+ logger.error(
+ std::string("Expected value of type \"") +
+ innerType->getName() +
+ std::string("\" but found constant \"") +
+ constant->getName() +
+ std::string(" of type \"") +
+ constantType->getName() + "\" instead.",
+ *owner);
+ } else if (!isValid) {
+ logger.error("Identifier \"" + constantName +
+ "\" is not a valid " +
+ innerType->getName(),
+ *owner);
+ }
+
+ // Nevertheless, no matter what happened, set the value
+ // of the original magic variant to the given constant
+ *magicValuePtr = constant->getValue();
+ }
+
+ // Decrement the number of magic values, call the callback
+ // function if all magic values have been resolved
+ (*magicCount)--;
+ if ((*magicCount) == 0 && (*isAsync)) {
+ resultCallback(resolved, owner, logger);
+ }
+ });
+ });
+
+ // Now we are asynchronous
+ (*isAsync) = true;
+
+ // Directly call the callback function if there were no magic values
+ // involved
+ if ((*magicCount) == 0) {
+ resultCallback(resolved, owner, logger);
+ }
+ });
+}
+
+bool ParserScope::resolveTypeWithValue(const std::string &name,
+ Handle<Node> owner, Variant &value,
+ Logger &logger,
+ ResolutionResultCallback resultCallback)
+{
+ return resolveTypeWithValue(Utils::split(name, '.'), owner, value, logger,
+ resultCallback);
+}
+
bool ParserScope::performDeferredResolution(Logger &logger)
{
// Repeat the resolution process as long as something has changed in the
@@ -304,7 +459,8 @@ bool ParserScope::performDeferredResolution(Logger &logger)
// Output error messages for all elements for which resolution did not
// succeed.
- for (const auto &failed : deferred) {
+ for (auto &failed : deferred) {
+ failed.fail(logger);
logger.error(std::string("Could not resolve ") + failed.type.name +
std::string(" \"") + Utils::join(failed.path, ".") +
std::string("\""),
diff --git a/src/core/parser/ParserScope.hpp b/src/core/parser/ParserScope.hpp
index 2378967..c49acd3 100644
--- a/src/core/parser/ParserScope.hpp
+++ b/src/core/parser/ParserScope.hpp
@@ -33,8 +33,7 @@
* @file ParserScope.hpp
*
* Contains the ParserScope class used for resolving references based on the
- *current
- * parser state.
+ * current parser state.
*
* @author Andreas Stöckel (astoecke@techfak.uni-bielefeld.de)
*/
@@ -45,6 +44,7 @@ namespace ousia {
class CharReader;
class Logger;
class ParserScope;
+class Variant;
/**
* Callback function type used for creating a dummy object while no correct
@@ -55,9 +55,13 @@ using ResolutionImposterCallback = std::function<Rooted<Node>()>;
/**
* Callback function type called whenever the result of a resolution is
* available.
+ *
+ * @param resolved is the new, resolved node.
+ * @param owner is the node that was passed as "owner".
+ * @param logger is the logger to which errors should be logged.
*/
-using ResolutionResultCallback =
- std::function<void(Handle<Node>, Logger &logger)>;
+using ResolutionResultCallback = std::function<void(Handle<Node> resolved,
+ Handle<Node> owner, Logger &logger)>;
/**
* Base class for the
@@ -90,14 +94,14 @@ public:
* 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 path is the path for which a node 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,
+ Rooted<Node> resolve(const Rtti &type, const std::vector<std::string> &path,
Logger &logger);
};
@@ -167,6 +171,15 @@ public:
*/
bool resolve(const std::unordered_multiset<const Node *> &ignore,
Logger &logger);
+
+ /**
+ * Inform the callee about the failure by calling the callback function with
+ * "nullptr" as resolved element.
+ *
+ * @param logger is the logger instance to which error messages should be
+ * logged.
+ */
+ void fail(Logger &logger);
};
/**
@@ -396,8 +409,9 @@ public:
* 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 path is the path for which a node should be resolved.
+ * @param owner is the node for which the resolution takes place.
* @param logger is the logger instance into which resolution problems
* should be logged.
* @param imposterCallback is the callback function that is called if
@@ -410,15 +424,14 @@ public:
* 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 owner is the node for which the resolution takes place.
* @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,
- Handle<Node> owner = nullptr);
+ bool resolve(const Rtti &type, const std::vector<std::string> &path,
+ Handle<Node> owner, Logger &logger,
+ ResolutionImposterCallback imposterCallback,
+ ResolutionResultCallback resultCallback);
/**
* Tries to resolve a node for the given type and path for all nodes
@@ -426,21 +439,21 @@ public:
* 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 path is the path for which a node should be resolved.
+ * @param owner is the node for which the resolution takes place.
* @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 owner is the node for which the resolution takes place.
* @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,
- Handle<Node> owner = nullptr);
+ bool resolve(const Rtti &type, const std::vector<std::string> &path,
+ Handle<Node> owner, Logger &logger,
+ ResolutionResultCallback resultCallback);
/**
* Tries to resolve a node for the given type and path for all nodes
@@ -453,6 +466,7 @@ public:
*
* @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 owner is the node for which the resolution takes place.
* @param logger is the logger instance into which resolution problems
* should be logged.
* @param imposterCallback is the callback function that is called if
@@ -465,24 +479,17 @@ public:
* 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 owner is the node for which the resolution takes place.
* @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,
- Handle<Node> owner = nullptr)
+ bool resolve(const std::vector<std::string> &path, Handle<Node> owner,
+ Logger &logger, ResolutionImposterCallback imposterCallback,
+ ResolutionResultCallback resultCallback)
{
- return resolve(
- path, typeOf<T>(), logger,
- [imposterCallback]() -> Rooted<Node> { return imposterCallback(); },
- [resultCallback](Handle<Node> node, Logger &logger) {
- resultCallback(node.cast<T>(), logger);
- },
- owner);
+ return resolve(typeOf<T>(), path, owner, logger, imposterCallback,
+ resultCallback);
}
/**
@@ -493,26 +500,21 @@ public:
*
* @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 owner is the node for which the resolution takes place.
* @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 owner is the node for which the resolution takes place.
* @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,
- Handle<Node> owner = nullptr)
+ bool resolve(const std::vector<std::string> &path, Handle<Node> owner,
+ Logger &logger, ResolutionResultCallback resultCallback)
{
- return resolve(path, typeOf<T>(), logger,
- [resultCallback](Handle<Node> node, Logger &logger) {
- resultCallback(node.cast<T>(), logger);
- },
- owner);
+ return resolve(typeOf<T>(), path, owner, logger, resultCallback);
}
/**
@@ -527,6 +529,7 @@ public:
* @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 owner is the node for which the resolution takes place.
* @param logger is the logger instance into which resolution problems
* should be logged.
* @param imposterCallback is the callback function that is called if
@@ -539,19 +542,17 @@ public:
* 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 owner is the node for which the resolution takes place.
* @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,
- Handle<Node> owner = nullptr)
+ bool resolve(const std::string &name, Handle<Node> owner, Logger &logger,
+ ResolutionImposterCallback imposterCallback,
+ ResolutionResultCallback resultCallback)
{
- return resolve<T>(Utils::split(name, '.'), logger, imposterCallback,
- resultCallback, owner);
+ return resolve<T>(Utils::split(name, '.'), owner, logger,
+ imposterCallback, resultCallback);
}
/**
@@ -563,26 +564,119 @@ public:
* @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 owner is the node for which the resolution takes place.
* @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 owner is the node for which the resolution takes place.
* @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,
- Handle<Node> owner = nullptr)
+ bool resolve(const std::string &name, Handle<Node> owner, Logger &logger,
+ ResolutionResultCallback resultCallback)
{
- return resolve<T>(Utils::split(name, '.'), logger, resultCallback,
- owner);
+ return resolve<T>(Utils::split(name, '.'), owner, logger,
+ resultCallback);
}
/**
+ * Resolves a typesystem type. Makes sure an array type is returned if an
+ * array type is requested.
+ *
+ * @param path is the path for which a node should be resolved.
+ * @param owner is the node for which the resolution takes place.
+ * @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.
+ * @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 resolveType(const std::vector<std::string> &path, Handle<Node> owner,
+ Logger &logger, ResolutionResultCallback resultCallback);
+
+ /**
+ * Resolves a typesystem type. Makes sure an array type is returned if an
+ * array type is requested.
+ *
+ * @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 owner is the node for which the resolution takes place.
+ * @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.
+ * @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 resolveType(const std::string &name, Handle<Node> owner,
+ Logger &logger, ResolutionResultCallback resultCallback);
+
+ /**
+ * Resolves a type and makes sure the corresponding value is of the correct
+ * type.
+ *
+ * <b>Warning:</b> This function is extremely dangerous as you have to make
+ * sure that the "value" reference stays alife as long as the "owner" is
+ * valid. This is especially problematic as internally references at parts
+ * of "value" may be kept. Test usages of this function well!
+ *
+ * @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 owner is the node for which the resolution takes place.
+ * @param value is a reference at the Variant that represents the value for
+ * which the type should be looked up. The value must be valid as long as
+ * the owner node is valid (so it should be a part of the owner).
+ * @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.
+ * @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 resolveTypeWithValue(const std::vector<std::string> &path,
+ Handle<Node> owner, Variant &value,
+ Logger &logger, ResolutionResultCallback resultCallback);
+
+ /**
+ * Resolves a type and makes sure the corresponding value is of the correct
+ * type.
+ *
+ * <b>Warning:</b> This function is extremely dangerous as you have to make
+ * sure that the "value" reference stays alife as long as the "owner" is
+ * valid. This is especially problematic as internally references at parts
+ * of "value" may be kept. Test usages of this function well!
+ *
+ * @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 owner is the node for which the resolution takes place.
+ * @param value is a reference at the Variant that represents the value for
+ * which the type should be looked up. The value must be valid as long as
+ * the owner node is valid (so it should be a part of the owner).
+ * @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.
+ * @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 resolveTypeWithValue(const std::string &name, Handle<Node> owner,
+ Variant &value, Logger &logger, ResolutionResultCallback resultCallback);
+
+ /**
* Tries to resolve all currently deferred resolution steps. The list of
* pending deferred resolutions is cleared after this function has run.
*