summaryrefslogtreecommitdiff
path: root/src/core/parser
diff options
context:
space:
mode:
authorAndreas Stöckel <astoecke@techfak.uni-bielefeld.de>2015-03-03 20:20:40 +0100
committerAndreas Stöckel <andreas@somweyr.de>2015-03-03 20:20:40 +0100
commit42c0480b4fbf80afa0c5b13650a0af74311d7202 (patch)
tree13f40104b4d8ebcb394f9adbf0b6a723889acea9 /src/core/parser
parentb6ec0740e027fc1bc7f6d2513583187061bc8f0a (diff)
Implemented annotation handling
Diffstat (limited to 'src/core/parser')
-rw-r--r--src/core/parser/stack/DocumentHandler.cpp151
-rw-r--r--src/core/parser/stack/DocumentHandler.hpp3
-rw-r--r--src/core/parser/stack/Handler.cpp6
-rw-r--r--src/core/parser/stack/Handler.hpp18
-rw-r--r--src/core/parser/stack/Stack.cpp87
-rw-r--r--src/core/parser/stack/Stack.hpp7
6 files changed, 207 insertions, 65 deletions
diff --git a/src/core/parser/stack/DocumentHandler.cpp b/src/core/parser/stack/DocumentHandler.cpp
index 26b9b6e..486ce81 100644
--- a/src/core/parser/stack/DocumentHandler.cpp
+++ b/src/core/parser/stack/DocumentHandler.cpp
@@ -127,19 +127,23 @@ void DocumentChildHandler::createPath(const size_t &firstFieldIdx,
scope().setFlag(ParserFlag::POST_EXPLICIT_FIELDS, false);
}
-bool DocumentChildHandler::startCommand(Variant::mapType &args)
+static std::string extractNameAttribute(Variant::mapType &args)
{
// Extract the special "name" attribute from the input arguments.
// The remaining attributes will be forwarded to the newly constructed
// element.
- std::string nameAttr;
- {
- auto it = args.find("name");
- if (it != args.end()) {
- nameAttr = it->second.asString();
- args.erase(it);
- }
+ std::string res;
+ auto it = args.find("name");
+ if (it != args.end()) {
+ res = it->second.asString();
+ args.erase(it);
}
+ return res;
+}
+
+bool DocumentChildHandler::startCommand(Variant::mapType &args)
+{
+ std::string nameAttr = extractNameAttribute(args);
scope().setFlag(ParserFlag::POST_HEAD, true);
while (true) {
@@ -190,9 +194,9 @@ bool DocumentChildHandler::startCommand(Variant::mapType &args)
"Data or structure commands have already been "
"given, command \"") +
name() + std::string(
- "\" is not interpreted explicit "
- "field. Move explicit field "
- "references to the beginning."),
+ "\" is not interpreted explicit "
+ "field. Move explicit field "
+ "references to the beginning."),
location());
} else {
Rooted<DocumentField> field{new DocumentField(
@@ -252,18 +256,109 @@ bool DocumentChildHandler::startCommand(Variant::mapType &args)
// parent structure element
scope().setFlag(ParserFlag::POST_EXPLICIT_FIELDS, true);
- // Bush the entity onto the stack
+ // Push the entity onto the stack
entity->setLocation(location());
scope().push(entity);
return true;
}
}
-bool DocumentChildHandler::startAnnotation(Variant::mapType &args,
- AnnotationType annotationType)
+bool DocumentChildHandler::startAnnotation(Variant::mapType &args)
{
- // TODO: Handle annotation
- return false;
+ std::string nameAttr = extractNameAttribute(args);
+
+ scope().setFlag(ParserFlag::POST_HEAD, true);
+
+ size_t fieldIdx;
+ DocumentEntity *parent;
+ while (true) {
+ Rooted<Node> parentNode = scope().getLeaf();
+
+ // Make sure the parent node is a DocumentField
+ if (parentNode->isa(&RttiTypes::Document)) {
+ logger().error(
+ "Cannot start or end annotation at the document level.",
+ location());
+ return false;
+ }
+ assert(parentNode->isa(&RttiTypes::DocumentField));
+
+ preamble(parentNode, fieldIdx, parent);
+
+ if (!parent->getDescriptor()
+ ->getFieldDescriptors()[fieldIdx]
+ ->isPrimitive()) {
+ break;
+ }
+
+ // If we are inside a primitive field and have transparent elements on
+ // the stack we unwind the stack until we are inside
+ // a non-primitive field.
+ if (scope().getLeaf().cast<DocumentField>()->transparent) {
+ // if we have transparent elements above us in the structure
+ // tree we try to unwind them before we give up.
+ // pop the implicit field.
+ scope().pop(logger());
+ // pop the implicit element.
+ scope().pop(logger());
+ continue;
+ }
+ }
+
+ // Create the anchor
+ Rooted<Anchor> anchor = parent->createChildAnchor(fieldIdx);
+ anchor->setLocation(location());
+
+ // resolve the AnnotationClass
+ Rooted<AnnotationClass> annoClass;
+ if (!name().empty()) {
+ annoClass = scope().resolve<AnnotationClass>(Utils::split(name(), ':'),
+ logger());
+ }
+
+ switch (type()) {
+ case HandlerType::ANNOTATION_START: {
+ // Create the AnnotationEntity itself.
+ if (annoClass == nullptr) {
+ // if we could not resolve the name, throw an exception.
+ throw LoggableException(
+ std::string("\"") + name() + "\" could not be resolved.",
+ location());
+ }
+ Rooted<Document> doc = scope().selectOrThrow<Document>();
+ Rooted<AnnotationEntity> anno = doc->createChildAnnotation(
+ annoClass, anchor, nullptr, args, nameAttr);
+
+ // Push the entity onto the stack
+ anno->setLocation(location());
+ scope().push(anno);
+ break;
+ }
+ case HandlerType::ANNOTATION_END: {
+ // if we want to end an annotation, look for the matching start
+ // Anchor ...
+ Rooted<Anchor> start =
+ parent->searchStartAnchor(fieldIdx, annoClass, nameAttr);
+ if (start == nullptr) {
+ logger().error(
+ "Did not find matching annotation start for annotation "
+ "end.",
+ *anchor);
+ parent->removeStructureNodeFromField(anchor, fieldIdx);
+ return false;
+ }
+ // ... and set the end Anchor.
+ start->getAnnotation()->setEnd(anchor);
+ break;
+ }
+ default:
+ throw OusiaException(
+ "Internal Error: Invalid handler type in startAnnotation");
+ }
+ // We're past the region in which explicit fields can be defined in the
+ // parent structure element
+ scope().setFlag(ParserFlag::POST_EXPLICIT_FIELDS, true);
+ return true;
}
bool DocumentChildHandler::startToken(Handle<Node> node)
@@ -281,11 +376,23 @@ DocumentChildHandler::EndTokenResult DocumentChildHandler::endToken(
void DocumentChildHandler::end()
{
- // In case of explicit fields we do not want to pop something from the
- // stack.
- if (!isExplicitField) {
- // pop the "main" element.
- scope().pop(logger());
+ switch (type()) {
+ case HandlerType::COMMAND:
+ case HandlerType::ANNOTATION_START:
+ // In case of explicit fields we do not want to pop something from
+ // the
+ // stack.
+ if (!isExplicitField) {
+ // pop the "main" element.
+ scope().pop(logger());
+ }
+ break;
+ case HandlerType::ANNOTATION_END:
+ // We have nothing to pop from the stack
+ break;
+ case HandlerType::TOKEN:
+ // TODO
+ break;
}
}
@@ -481,4 +588,4 @@ namespace RttiTypes {
const Rtti DocumentField = RttiBuilder<ousia::parser_stack::DocumentField>(
"DocumentField").parent(&Node);
}
-}
+} \ No newline at end of file
diff --git a/src/core/parser/stack/DocumentHandler.hpp b/src/core/parser/stack/DocumentHandler.hpp
index 0e35558..6f9f4a2 100644
--- a/src/core/parser/stack/DocumentHandler.hpp
+++ b/src/core/parser/stack/DocumentHandler.hpp
@@ -167,8 +167,7 @@ public:
DocumentChildHandler(const HandlerData &handlerData);
bool startCommand(Variant::mapType &args) override;
- bool startAnnotation(Variant::mapType &args,
- AnnotationType annotationType) override;
+ bool startAnnotation(Variant::mapType &args) override;
bool startToken(Handle<Node> node) override;
EndTokenResult endToken(const Token &token, Handle<Node> node) override;
void end() override;
diff --git a/src/core/parser/stack/Handler.cpp b/src/core/parser/stack/Handler.cpp
index c01e74c..ef6ca8b 100644
--- a/src/core/parser/stack/Handler.cpp
+++ b/src/core/parser/stack/Handler.cpp
@@ -109,8 +109,7 @@ bool EmptyHandler::startCommand(Variant::mapType &args)
return true;
}
-bool EmptyHandler::startAnnotation(Variant::mapType &args,
- Handler::AnnotationType annotationType)
+bool EmptyHandler::startAnnotation(Variant::mapType &args)
{
// Do not support annotations. Annotations are too complicated for poor
// EmptyHandler.
@@ -165,8 +164,7 @@ bool StaticHandler::startCommand(Variant::mapType &args)
return true;
}
-bool StaticHandler::startAnnotation(Variant::mapType &args,
- Handler::AnnotationType annotationType)
+bool StaticHandler::startAnnotation(Variant::mapType &args)
{
return false;
}
diff --git a/src/core/parser/stack/Handler.hpp b/src/core/parser/stack/Handler.hpp
index 67fde06..d85848a 100644
--- a/src/core/parser/stack/Handler.hpp
+++ b/src/core/parser/stack/Handler.hpp
@@ -209,13 +209,6 @@ protected:
public:
/**
- * Enum representing the type of the annotation a Handle instance handles.
- * It may either handle the start of an annotation or the end of an
- * annotation.
- */
- enum class AnnotationType { START, END };
-
- /**
* Enum type representing the possible outcomes of the endToken() method.
*/
enum class EndTokenResult { ENDED_THIS, ENDED_HIDDEN, ENDED_NONE };
@@ -347,11 +340,8 @@ public:
* accessed using the name() method.
*
* @param args is a map from strings to variants (argument name and value).
- * @param type specifies whether this handler should handle the start of an
- * annotation or the end of an annotation.
*/
- virtual bool startAnnotation(Variant::mapType &args,
- AnnotationType annotationType) = 0;
+ virtual bool startAnnotation(Variant::mapType &args) = 0;
/**
* Called whenever the handler should handle the start of a token. This
@@ -442,8 +432,7 @@ protected:
public:
bool startCommand(Variant::mapType &args) override;
- bool startAnnotation(Variant::mapType &args,
- AnnotationType annotationType) override;
+ bool startAnnotation(Variant::mapType &args) override;
bool startToken(Handle<Node> node) override;
EndTokenResult endToken(const Token &token, Handle<Node> node) override;
void end() override;
@@ -468,8 +457,7 @@ protected:
public:
bool startCommand(Variant::mapType &args) override;
- bool startAnnotation(Variant::mapType &args,
- AnnotationType annotationType) override;
+ bool startAnnotation(Variant::mapType &args) override;
bool startToken(Handle<Node> node) override;
EndTokenResult endToken(const Token &token, Handle<Node> node) override;
void end() override;
diff --git a/src/core/parser/stack/Stack.cpp b/src/core/parser/stack/Stack.cpp
index f341f1d..23c857a 100644
--- a/src/core/parser/stack/Stack.cpp
+++ b/src/core/parser/stack/Stack.cpp
@@ -416,6 +416,17 @@ private:
void handleData();
/**
+ * Called whenever the annotationStart or annotationEnd methods are called.
+ *
+ * @param name is the class name of the annotation.
+ * @param args contains the arguments that are passed to the annotation.
+ * @param range is set to true if this is a ranged annotation.
+ * @param type specifies whether this is a start or end annotation.
+ */
+ void handleAnnotationStartEnd(const Variant &name, Variant::mapType args,
+ bool range, HandlerType type);
+
+ /**
* Called whenever there is a token waiting to be processed. If possible
* tries to end a current handler with this token or to start a new handler
* with the token.
@@ -444,9 +455,9 @@ public:
void commandStart(const Variant &name, const Variant::mapType &args,
bool range);
- void annotationStart(const Variant &className, const Variant &args,
+ void annotationStart(const Variant &className, const Variant::mapType &args,
bool range);
- void annotationEnd(const Variant &className, const Variant &elementName);
+ void annotationEnd(const Variant &className, const Variant::mapType &args);
void rangeEnd();
void fieldStart(bool isDefault);
void fieldEnd();
@@ -645,8 +656,11 @@ bool StackImpl::prepareCurrentHandler(bool startImplicitDefaultField)
// If the current field already had a default field or is not valid,
// end it and repeat
- if ((info.hadDefaultField || !startImplicitDefaultField) ||
- !info.valid) {
+ bool canHaveImplicitDefaultField =
+ info.type() == HandlerType::COMMAND ||
+ info.type() == HandlerType::TOKEN || (info.type() == HandlerType::ANNOTATION_START && info.range);
+ if (info.hadDefaultField || !startImplicitDefaultField || !info.valid ||
+ !canHaveImplicitDefaultField) {
// We cannot end the command if it is marked as "range" command
if (info.range) {
return false;
@@ -657,11 +671,6 @@ bool StackImpl::prepareCurrentHandler(bool startImplicitDefaultField)
continue;
}
- // Abort if starting new default fields is not allowed here
- if (!startImplicitDefaultField) {
- return false;
- }
-
// Try to start a new default field, abort if this did not work
bool isDefault = true;
if (!info.handler->fieldStart(isDefault, info.fieldIdx)) {
@@ -805,6 +814,44 @@ void StackImpl::handleFieldEnd(bool endRange)
info.fieldEnd();
}
+void StackImpl::handleAnnotationStartEnd(const Variant &name,
+ Variant::mapType args, bool range,
+ HandlerType type)
+{
+ // Prepare the stack -- make sure all overdue handlers are ended and
+ // we currently are in an open field
+ if (stack.empty() || !prepareCurrentHandler()) {
+ throw LoggableException("Did not expect an annotation start here");
+ }
+
+ // Find the special target state TODO: Is there some better solution?
+ const State *state = findTargetState("*");
+ if (state == nullptr || !currentInfo().state().supportsAnnotations) {
+ throw LoggableException("Cannot handle annotations here");
+ }
+
+ // If we're currently in an invalid subtree, just eat the data and abort
+ if (!handlersValid()) {
+ return;
+ }
+
+ // Instantiate the handler and push it onto the stack
+ HandlerConstructor ctor =
+ state->elementHandler ? state->elementHandler : EmptyHandler::create;
+ std::shared_ptr<Handler> handler{ctor(
+ {ctx, *this, *state, {name.asString(), name.getLocation()}, type})};
+ stack.emplace_back(handler);
+
+ // Call the startAnnotation method of the newly created handler, store the
+ // valid flag
+ HandlerInfo &info = currentInfo();
+ info.valid = handler->startAnnotation(args);
+ info.range = range;
+ if (type == HandlerType::ANNOTATION_END) {
+ endCurrentHandler();
+ }
+}
+
/* Class StackImpl public functions */
void StackImpl::commandStart(const Variant &name, const Variant::mapType &args,
@@ -904,16 +951,18 @@ void StackImpl::commandStart(const Variant &name, const Variant::mapType &args,
}
}
-void StackImpl::annotationStart(const Variant &className, const Variant &args,
- bool range)
+void StackImpl::annotationStart(const Variant &className,
+ const Variant::mapType &args, bool range)
{
- // TODO
+ handleAnnotationStartEnd(className, args, range,
+ HandlerType::ANNOTATION_START);
}
void StackImpl::annotationEnd(const Variant &className,
- const Variant &elementName)
+ const Variant::mapType &args)
{
- // TODO
+ handleAnnotationStartEnd(className, args, false,
+ HandlerType::ANNOTATION_END);
}
void StackImpl::rangeEnd() { handleFieldEnd(true); }
@@ -1064,8 +1113,8 @@ void Stack::commandStart(const Variant &name, const Variant::mapType &args,
impl->commandStart(name, args, range);
}
-void Stack::annotationStart(const Variant &className, const Variant &args,
- bool range)
+void Stack::annotationStart(const Variant &className,
+ const Variant::mapType &args, bool range)
{
#if STACK_DEBUG_OUTPUT
std::cout << "STACK: annotationStart " << className << " " << args << " "
@@ -1074,13 +1123,13 @@ void Stack::annotationStart(const Variant &className, const Variant &args,
impl->annotationStart(className, args, range);
}
-void Stack::annotationEnd(const Variant &className, const Variant &elementName)
+void Stack::annotationEnd(const Variant &className, const Variant::mapType &args)
{
#if STACK_DEBUG_OUTPUT
- std::cout << "STACK: annotationEnd " << className << " " << elementName
+ std::cout << "STACK: annotationEnd " << className << " " << args
<< std::endl;
#endif
- impl->annotationEnd(className, elementName);
+ impl->annotationEnd(className, args);
}
void Stack::rangeEnd()
diff --git a/src/core/parser/stack/Stack.hpp b/src/core/parser/stack/Stack.hpp
index 6d42f10..cbf4bc2 100644
--- a/src/core/parser/stack/Stack.hpp
+++ b/src/core/parser/stack/Stack.hpp
@@ -114,16 +114,17 @@ public:
* to the annotation.
* @param range if true, the annotation fields have an explicit range.
*/
- void annotationStart(const Variant &className, const Variant &args,
+ void annotationStart(const Variant &className, const Variant::mapType &args,
bool range = false);
/**
* Function that should be called whenever an annotation ends.
*
* @param name is the name of the annotation class that was ended.
- * @param annotationName is the name of the annotation that was ended.
+ * @param args contains the arguments that were passed to the annotation end
+ * handler.
*/
- void annotationEnd(const Variant &className, const Variant &elementName);
+ void annotationEnd(const Variant &className, const Variant::mapType &args);
/**
* Function the should be called whenever a ranged command or annotation