diff options
Diffstat (limited to 'src/core')
-rw-r--r-- | src/core/parser/stack/DocumentHandler.cpp | 151 | ||||
-rw-r--r-- | src/core/parser/stack/DocumentHandler.hpp | 3 | ||||
-rw-r--r-- | src/core/parser/stack/Handler.cpp | 6 | ||||
-rw-r--r-- | src/core/parser/stack/Handler.hpp | 18 | ||||
-rw-r--r-- | src/core/parser/stack/Stack.cpp | 87 | ||||
-rw-r--r-- | src/core/parser/stack/Stack.hpp | 7 |
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 |