summaryrefslogtreecommitdiff
path: root/src/core/parser
diff options
context:
space:
mode:
authorAndreas Stöckel <astoecke@techfak.uni-bielefeld.de>2015-01-18 13:46:06 +0100
committerAndreas Stöckel <astoecke@techfak.uni-bielefeld.de>2015-01-18 13:46:06 +0100
commitdb51a874964b038c69f1336a8a659ae40471e26b (patch)
treeb0eae3727241be330321c5bd1de4d1695ff6578d /src/core/parser
parent5c832e5cc0d2ff948816bd4a492189435efa8578 (diff)
Implemented storing locations in the ParserStack, improved parsing typesystems
Diffstat (limited to 'src/core/parser')
-rw-r--r--src/core/parser/ParserStack.cpp15
-rw-r--r--src/core/parser/ParserStack.hpp41
-rw-r--r--src/core/parser/Scope.cpp66
-rw-r--r--src/core/parser/Scope.hpp66
4 files changed, 123 insertions, 65 deletions
diff --git a/src/core/parser/ParserStack.cpp b/src/core/parser/ParserStack.cpp
index caf2116..9cf782f 100644
--- a/src/core/parser/ParserStack.cpp
+++ b/src/core/parser/ParserStack.cpp
@@ -63,11 +63,11 @@ void Handler::child(std::shared_ptr<Handler> handler)
HandlerInstance HandlerDescriptor::create(const ParserContext &ctx,
std::string name, State parentState,
- bool isChild,
- Variant::mapType &args) const
+ bool isChild, Variant::mapType &args,
+ const SourceLocation &location) const
{
Handler *h;
- HandlerData data{ctx, name, targetState, parentState, isChild};
+ HandlerData data{ctx, name, targetState, parentState, isChild, location};
if (ctor) {
h = ctor(data);
} else {
@@ -115,7 +115,8 @@ std::set<std::string> ParserStack::expectedCommands(State state)
return res;
}
-void ParserStack::start(std::string name, Variant::mapType &args)
+void ParserStack::start(std::string name, Variant::mapType &args,
+ const SourceLocation &location)
{
// Fetch the current handler and the current state
const HandlerInstance *h = stack.empty() ? nullptr : &stack.top();
@@ -143,11 +144,11 @@ void ParserStack::start(std::string name, Variant::mapType &args)
}
// Instantiate the handler and call its start function
- stack.emplace(
- descr->create(ctx, name, curState, isChild, args));
+ stack.emplace(descr->create(ctx, name, curState, isChild, args, location));
}
-void ParserStack::start(std::string name, const Variant::mapType &args)
+void ParserStack::start(std::string name, const Variant::mapType &args,
+ const SourceLocation &location)
{
Variant::mapType argsCopy(args);
start(name, argsCopy);
diff --git a/src/core/parser/ParserStack.hpp b/src/core/parser/ParserStack.hpp
index 43d6529..aa196e7 100644
--- a/src/core/parser/ParserStack.hpp
+++ b/src/core/parser/ParserStack.hpp
@@ -86,6 +86,11 @@ struct HandlerData {
const bool isChild;
/**
+ * Current source code location.
+ */
+ const SourceLocation location;
+
+ /**
* Constructor of the HandlerData class.
*
* @param ctx is the parser context the handler should be executed in.
@@ -94,14 +99,16 @@ struct HandlerData {
* @param parentState is the state of the parent command.
* @param isChild specifies whether this handler was called not for the
* command that was specified in the state machine but a child command.
+ * @param location is the location at which the handler is created.
*/
HandlerData(const ParserContext &ctx, std::string name, State state,
- State parentState, bool isChild)
+ State parentState, bool isChild, const SourceLocation location)
: ctx(ctx),
name(std::move(name)),
state(state),
parentState(parentState),
- isChild(isChild){};
+ isChild(isChild),
+ location(location){};
};
/**
@@ -123,28 +130,29 @@ public:
* @param data is a structure containing all data being passed to the
* handler.
*/
- Handler(const HandlerData &handlerData) : handlerData(handlerData) {};
+ Handler(const HandlerData &handlerData) : handlerData(handlerData){};
/**
* Virtual destructor.
*/
virtual ~Handler(){};
-
- const std::string& name() {return handlerData.name;}
+ const std::string &name() { return handlerData.name; }
- Scope &scope() {return handlerData.ctx.scope;}
+ Scope &scope() { return handlerData.ctx.scope; }
- Registry &registry() {return handlerData.ctx.registry;}
+ Registry &registry() { return handlerData.ctx.registry; }
Manager &manager() { return handlerData.ctx.manager; }
Logger &logger() { return handlerData.ctx.logger; }
- State state() {return handlerData.state; }
+ State state() { return handlerData.state; }
State parentState() { return handlerData.parentState; }
+ SourceLocation location() { return handlerData.location; }
+
bool isChild() { return handlerData.isChild; }
/**
@@ -279,7 +287,8 @@ struct HandlerDescriptor {
*/
HandlerInstance create(const ParserContext &ctx, std::string name,
State parentState, bool isChild,
- Variant::mapType &args) const;
+ Variant::mapType &args,
+ const SourceLocation &location) const;
};
/**
@@ -294,9 +303,9 @@ private:
ParserContext &ctx;
/**
- * User specified data that will be passed to all handlers.
+ * Current location in the source code.
*/
- void *userData;
+ SourceLocation location;
/**
* Map containing all registered command names and the corresponding
@@ -369,16 +378,22 @@ public:
*
* @param name is the name of the command.
* @param args is a map from strings to variants (argument name and value).
+ * @param location is the location in the source file at which the command
+ * starts.
*/
- void start(std::string name, Variant::mapType &args);
+ void start(std::string name, Variant::mapType &args,
+ const SourceLocation &location = SourceLocation{});
/**
* Function that should be called whenever a new command starts.
*
* @param name is the name of the command.
* @param args is a map from strings to variants (argument name and value).
+ * @param location is the location in the source file at which the command
+ * starts.
*/
- void start(std::string name, const Variant::mapType &args);
+ void start(std::string name, const Variant::mapType &args,
+ const SourceLocation &location = SourceLocation{});
/**
* Function called whenever a command ends.
diff --git a/src/core/parser/Scope.cpp b/src/core/parser/Scope.cpp
index d76af9c..6e7dceb 100644
--- a/src/core/parser/Scope.cpp
+++ b/src/core/parser/Scope.cpp
@@ -59,11 +59,11 @@ Rooted<Node> ScopeBase::resolve(const std::vector<std::string> &path,
// 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.error(std::string("The reference \"") +
+ Utils::join(path, ".") + ("\" is ambigous!"));
logger.note("Referenced objects are:");
for (const ResolutionResult &r : res) {
- logger.note(std::string("\t") + Utils::join(r.path(), "."));
+ logger.note(Utils::join(r.path(), "."));
}
}
return res[0].node;
@@ -73,10 +73,16 @@ Rooted<Node> ScopeBase::resolve(const std::vector<std::string> &path,
/* 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)
+DeferredResolution::DeferredResolution(const NodeVector<Node> &nodes,
+ const std::vector<std::string> &path,
+ const RttiType &type,
+ ResolutionResultCallback resultCallback,
+ const SourceLocation &location)
+ : scope(nodes),
+ resultCallback(resultCallback),
+ path(path),
+ type(type),
+ location(location)
{
}
@@ -84,7 +90,12 @@ bool DeferredResolution::resolve(Logger &logger)
{
Rooted<Node> res = scope.resolve(path, type, logger);
if (res != nullptr) {
- resultCallback(res);
+ try {
+ resultCallback(res, logger);
+ }
+ catch (LoggableException ex) {
+ logger.log(ex);
+ }
return true;
}
return false;
@@ -106,30 +117,32 @@ 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)
+ Logger &logger, ResolutionImposterCallback imposterCallback,
+ ResolutionResultCallback resultCallback,
+ const SourceLocation &location)
{
- Rooted<Node> res = ScopeBase::resolve(path, type, logger);
- if (res != nullptr) {
- resultCallback(res);
- return true;
+ if (!resolve(path, type, logger, resultCallback, location)) {
+ resultCallback(imposterCallback(), logger);
+ return false;
}
- resultCallback(imposterCallback());
- deferred.emplace_back(nodes, path, type, resultCallback);
- return false;
+ return true;
}
bool Scope::resolve(const std::vector<std::string> &path, const RttiType &type,
- Logger &logger,
- std::function<void(Handle<Node>)> successCallback)
+ Logger &logger, ResolutionResultCallback resultCallback,
+ const SourceLocation &location)
{
Rooted<Node> res = ScopeBase::resolve(path, type, logger);
if (res != nullptr) {
- successCallback(res);
+ try {
+ resultCallback(res, logger);
+ }
+ catch (LoggableException ex) {
+ logger.log(ex, location);
+ }
return true;
}
- deferred.emplace_back(nodes, path, type, successCallback);
+ deferred.emplace_back(nodes, path, type, resultCallback, location);
return false;
}
@@ -157,14 +170,13 @@ bool Scope::performDeferredResolution(Logger &logger)
// 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));
+ std::string("Could not resolve a reference to \"") +
+ Utils::join(failed.path, ".") +
+ std::string("\" of type " + failed.type.name),
+ failed.location);
}
}
diff --git a/src/core/parser/Scope.hpp b/src/core/parser/Scope.hpp
index 2713c41..c99aa65 100644
--- a/src/core/parser/Scope.hpp
+++ b/src/core/parser/Scope.hpp
@@ -43,6 +43,18 @@ namespace parser {
class Scope;
/**
+ * Callback function type used for creating a dummy object while no correct
+ * object is available for resolution.
+ */
+using ResolutionImposterCallback = std::function<Rooted<Node>()>;
+
+/**
+ * Callback function type called whenever the result of a resolution is
+ * available.
+ */
+using ResolutionResultCallback = std::function<void(Handle<Node>, Logger &logger)>;
+
+/**
* The GuardedScope class takes care of pushing a Node instance into the
* name resolution stack of a Scope instance and poping this node once the
* ScopedScope instance is deletes. This way you cannot forget to pop a Node
@@ -148,7 +160,7 @@ private:
/**
* Callback function to be called when an element is successfully resolved.
*/
- std::function<void(Handle<Node>)> resultCallback;
+ ResolutionResultCallback resultCallback;
public:
/**
@@ -162,6 +174,11 @@ public:
const RttiType &type;
/**
+ * Position at which the resolution was triggered.
+ */
+ const SourceLocation location;
+
+ /**
* Constructor of the DeferredResolutionScope class. Copies the given
* arguments.
*
@@ -172,11 +189,13 @@ public:
* @param type is the RttiType of the element that should be queried.
* @param resultCallback is the callback function that should be called if
* the desired element has indeed been found.
+ * @param location is the location at which the resolution was triggered.
*/
DeferredResolution(const NodeVector<Node> &nodes,
const std::vector<std::string> &path,
const RttiType &type,
- std::function<void(Handle<Node>)> resultCallback);
+ ResolutionResultCallback resultCallback,
+ const SourceLocation &location = SourceLocation{});
/**
* Performs the actual deferred resolution and calls the resultCallback
@@ -267,34 +286,39 @@ 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 location is the location in the current source file in which the
+ * resolution was triggered.
* @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 RttiType &type,
- Logger &logger, std::function<Rooted<Node>()> imposterCallback,
- std::function<void(Handle<Node>)> resultCallback);
+ Logger &logger, ResolutionImposterCallback imposterCallback,
+ ResolutionResultCallback resultCallback,
+ const SourceLocation &location = SourceLocation{});
/**
* Tries to resolve a node for the given type and path for all nodes
* currently on the stack, starting with the topmost node on the stack.
- * The "successCallback" is called when the resolution was successful, which
+ * 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 logger is the logger instance into which resolution problems
* should be logged.
- * @param successCallback is the callback function to which the result of
+ * @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 location is the location in the current source file in which the
+ * resolution was triggered.
* @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 RttiType &type,
- Logger &logger,
- std::function<void(Handle<Node>)> successCallback);
+ Logger &logger, ResolutionResultCallback resultCallback,
+ const SourceLocation &location = SourceLocation{});
/**
* Tries to resolve a node for the given type and path for all nodes
@@ -319,6 +343,8 @@ 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 location is the location in the current source file in which the
+ * resolution was triggered.
* @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.
@@ -326,41 +352,45 @@ public:
template <class T>
bool resolve(const std::vector<std::string> &path, Logger &logger,
std::function<Rooted<T>()> imposterCallback,
- std::function<void(Handle<T>)> successCallback)
+ std::function<void(Handle<T>, Logger&)> resultCallback,
+ const SourceLocation &location = SourceLocation{})
{
return resolve(
path, typeOf<T>(), logger,
[imposterCallback]() -> Rooted<Node> { return imposterCallback(); },
- [successCallback](Handle<Node> node) {
- successCallback(node.cast<T>());
- });
+ [resultCallback](Handle<Node> node, Logger &logger) {
+ resultCallback(node.cast<T>(), logger);
+ }, location);
}
/**
* Tries to resolve a node for the given type and path for all nodes
* currently on the stack, starting with the topmost node on the stack.
- * The "successCallback" is called when the resolution was successful, which
+ * The "resultCallback" is called when the resolution was successful, which
* may be at a later point in time.
*
* @tparam 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.
- * @param successCallback is the callback function to which the result of
+ * @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 location is the location in the current source file in which the
+ * resolution was triggered.
* @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>)> resultCallback)
+ std::function<void(Handle<T>, Logger&)> resultCallback,
+ const SourceLocation &location = SourceLocation{})
{
return resolve(path, typeOf<T>(), logger,
- [resultCallback](Handle<Node> node) {
- resultCallback(node.cast<T>());
- });
+ [resultCallback](Handle<Node> node, Logger &logger) {
+ resultCallback(node.cast<T>(), logger);
+ }, location);
}
/**