summaryrefslogtreecommitdiff
path: root/src/core/parser/stack/Stack.cpp
diff options
context:
space:
mode:
authorAndreas Stöckel <astoecke@techfak.uni-bielefeld.de>2015-02-15 00:12:04 +0100
committerAndreas Stöckel <astoecke@techfak.uni-bielefeld.de>2015-02-15 00:12:04 +0100
commit26766a588d988e635112878aba71c69c8f057c16 (patch)
tree3c68d600232365e1b6daad4b6441eabe70556d45 /src/core/parser/stack/Stack.cpp
parentc5fde12cbac6907da4e267492206b2df3dad01f8 (diff)
Renamed StateStack to Stack
Diffstat (limited to 'src/core/parser/stack/Stack.cpp')
-rw-r--r--src/core/parser/stack/Stack.cpp151
1 files changed, 110 insertions, 41 deletions
diff --git a/src/core/parser/stack/Stack.cpp b/src/core/parser/stack/Stack.cpp
index 1d83a68..b0df39b 100644
--- a/src/core/parser/stack/Stack.cpp
+++ b/src/core/parser/stack/Stack.cpp
@@ -21,20 +21,67 @@
#include <core/common/Utils.hpp>
#include <core/common/Exceptions.hpp>
#include <core/parser/ParserScope.hpp>
+#include <core/parser/ParserContext.hpp>
+#include "Handler.hpp"
#include "Stack.hpp"
+#include "State.hpp"
namespace ousia {
namespace parser_stack {
-/* Class StateStack */
+/* Class HandlerInfo */
+
+HandlerInfo::HandlerInfo() : HandlerInfo(nullptr) {}
+
+HandlerInfo::HandlerInfo(std::shared_ptr<Handler> handler)
+ : handler(handler),
+ fieldIdx(0),
+ inField(false),
+ inDefaultField(false),
+ inImplicitDefaultField(false),
+ hasDefaultField(false)
+{
+}
+
+HandlerInfo::~HandlerInfo()
+{
+ // Do nothing
+}
+
+void HandlerInfo::fieldStart(bool isDefault, bool isImplicit, bool isValid)
+{
+ inField = true;
+ inDefaultField = isDefault || isImplicit;
+ inImplicitDefaultField = isImplicit;
+ inValidField = isValid;
+ hasDefaultField = hasDefaultField || inDefaultField;
+ fieldIdx++;
+}
+
+void HandlerInfo::fieldEnd()
+{
+ inField = false;
+ inDefaultField = false;
+ inImplicitDefaultField = false;
+ inValidField = false;
+ if (fieldIdx > 0) {
+ fieldIdx--;
+ }
+}
+
+/* Helper functions */
/**
* Returns an Exception that should be thrown when a currently invalid command
* is thrown.
+ *
+ * @param name is the name of the command for which no state transition is
+ * found.
+ * @param expected is a set containing the names of the expected commands.
*/
-static LoggableException InvalidCommand(const std::string &name,
- const std::set<std::string> &expected)
+static LoggableException buildInvalidCommandException(
+ const std::string &name, const std::set<std::string> &expected)
{
if (expected.empty()) {
return LoggableException{
@@ -50,14 +97,22 @@ static LoggableException InvalidCommand(const std::string &name,
}
}
-StateStack::StateStack(
- ParserContext &ctx,
- const std::multimap<std::string, const State *> &states)
+/* Class Stack */
+
+Stack::Stack(ParserContext &ctx,
+ const std::multimap<std::string, const State *> &states)
: ctx(ctx), states(states)
{
+ // If the scope instance is not empty we need to deduce the current parser
+ // state
+ if (!ctx.getScope().isEmpty()) {
+ deduceState();
+ }
}
-bool StateStack::deduceState()
+Stack::~Stack() {}
+
+bool Stack::deduceState()
{
// Assemble all states
std::vector<const State *> states;
@@ -68,23 +123,28 @@ bool StateStack::deduceState()
// Fetch the type signature of the scope and derive all possible states,
// abort if no unique parser state was found
std::vector<const State *> possibleStates =
- StateDeductor(ctx.getScope().getStackTypeSignature(), states)
- .deduce();
- if (possibleStates.size() != 1) {
- ctx.getLogger().error(
- "Error while including file: Cannot deduce parser state.");
- return false;
+ StateDeductor(ctx.getScope().getStackTypeSignature(), states).deduce();
+ if (possibleStates.size() != 1U) {
+ throw LoggableException{
+ "Error while including file: Cannot deduce parser state."};
}
// Switch to this state by creating a dummy handler
const State *state = possibleStates[0];
- Handler *handler =
- DefaultHandler::create({ctx, "", *state, *state, SourceLocation{}});
- stack.emplace(handler);
+ stack.emplace(std::shared_ptr<Handler>{EmptyHandler::create({ctx, "", *state, *state, SourceLocation{}})});
+}
+
+bool Stack::handlersValid()
+{
+ for (auto it = stack.crbegin(); it != stack.crend(); it++) {
+ if (!it->valid) {
+ return false;
+ }
+ }
return true;
}
-std::set<std::string> StateStack::expectedCommands()
+std::set<std::string> Stack::expectedCommands()
{
const State *currentState = &(this->currentState());
std::set<std::string> res;
@@ -96,17 +156,17 @@ std::set<std::string> StateStack::expectedCommands()
return res;
}
-const State &StateStack::currentState()
+const State &Stack::currentState()
{
return stack.empty() ? States::None : stack.top()->state();
}
-std::string StateStack::currentCommandName()
+std::string Stack::currentCommandName()
{
return stack.empty() ? std::string{} : stack.top()->name();
}
-const State *StateStack::findTargetState(const std::string &name)
+const State *Stack::findTargetState(const std::string &name)
{
const State *currentState = &(this->currentState());
auto range = states.equal_range(name);
@@ -120,21 +180,26 @@ const State *StateStack::findTargetState(const std::string &name)
return nullptr;
}
-void StateStack::start(const std::string &name, Variant::mapType &args,
- const SourceLocation &location)
+void Stack::command(const Variant &name, const Variant::mapType &args)
{
- State const *targetState = findTargetState(name);
-// TODO: Andreas, please improve this.
-// if (!Utils::isIdentifier(name)) {
-// throw LoggableException(std::string("Invalid identifier \"") + name +
-// std::string("\""));
-// }
+ // Make sure the given identifier is valid
+ if (!Utils::isNamespacedIdentifier(name.asString())) {
+ throw LoggableException(std::string("Invalid identifier \"") +
+ name.asString() + std::string("\""), name);
+ }
+
+ // Try to find a target state for the given command
+ State const *targetState = findTargetState(name.asString());
+ // No target state is found, try to find a wildcard handler for the current
+ // state
if (targetState == nullptr) {
targetState = findTargetState("*");
}
+
+ // No handler has been found at all,
if (targetState == nullptr) {
- throw InvalidCommand(name, expectedCommands());
+ throw buildInvalidCommandException(name.asString(), expectedCommands());
}
// Fetch the associated constructor
@@ -145,20 +210,24 @@ void StateStack::start(const std::string &name, Variant::mapType &args,
// Canonicalize the arguments, allow additional arguments
targetState->arguments.validateMap(args, ctx.getLogger(), true);
- // Instantiate the handler and call its start function
- Handler *handler = ctor({ctx, name, *targetState, currentState(), location});
- handler->start(args);
- stack.emplace(handler);
-}
+ // Instantiate the handler and push it onto the stack
+ Handler *handler =
+ ctor({ctx, name.asString(), *targetState, currentState(), name.getLocation()});
+ stack.emplace_back(std::shared_ptr<Handler>{handler});
-void StateStack::start(std::string name, const Variant::mapType &args,
- const SourceLocation &location)
-{
- Variant::mapType argsCopy(args);
- start(name, argsCopy);
+ // Call the "start" method of the handler, store the result of the start
+ // method as the validity of the handler -- do not call the start method
+ // if the stack is currently invalid (as this may cause further, unwanted
+ // errors)
+ try {
+ stack.back().valid = handlersValid() && handler->start(args);
+ } catch (LoggableException ex) {
+ stack.back().valid = false;
+ logger.log(ex, )
+ }
}
-void StateStack::end()
+void Stack::end()
{
// Check whether the current command could be ended
if (stack.empty()) {
@@ -173,7 +242,7 @@ void StateStack::end()
inst->end();
}
-void StateStack::data(const std::string &data, int field)
+void Stack::data(const std::string &data, int field)
{
// Check whether there is any command the data can be sent to
if (stack.empty()) {