diff options
author | Andreas Stöckel <astoecke@techfak.uni-bielefeld.de> | 2015-02-16 18:58:12 +0100 |
---|---|---|
committer | Andreas Stöckel <andreas@somweyr.de> | 2015-02-16 18:58:12 +0100 |
commit | 75eea3bdd846a34c69be3d09f41ff4fae706628e (patch) | |
tree | af42dbf2fd9ea87884cd500367c4017293609863 /src/core | |
parent | 67f5572b423345a6e243516070a335a521459384 (diff) | |
parent | d4e835e5eaa40e5d7bfe2a51f03505bc27ddc8f7 (diff) |
Merge branch 'master' of ssh://somweyr.de/var/local/git/ousia
Diffstat (limited to 'src/core')
-rw-r--r-- | src/core/model/Document.cpp | 54 | ||||
-rw-r--r-- | src/core/model/Document.hpp | 132 | ||||
-rw-r--r-- | src/core/parser/stack/DocumentHandler.cpp | 381 | ||||
-rw-r--r-- | src/core/parser/stack/DocumentHandler.hpp | 78 |
4 files changed, 468 insertions, 177 deletions
diff --git a/src/core/model/Document.cpp b/src/core/model/Document.cpp index 848142d..2fcd20d 100644 --- a/src/core/model/Document.cpp +++ b/src/core/model/Document.cpp @@ -314,7 +314,7 @@ const NodeVector<StructureNode> &DocumentEntity::getField( return fields[idx]; } -void DocumentEntity::addStructureNode(Handle<StructureNode> s, const int &i) +void DocumentEntity::addStructureNode(Handle<StructureNode> s, const size_t &i) { // only add the new node if we don't have it already. auto it = fields[i].find(s); @@ -419,6 +419,15 @@ Rooted<StructuredEntity> DocumentEntity::createChildStructuredEntity( fieldName, std::move(name))}; } +Rooted<StructuredEntity> DocumentEntity::createChildStructuredEntity( + Handle<StructuredClass> descriptor, const size_t &fieldIdx, + Variant attributes, std::string name) +{ + return Rooted<StructuredEntity>{ + new StructuredEntity(subInst->getManager(), subInst, descriptor, + fieldIdx, std::move(attributes), std::move(name))}; +} + Rooted<DocumentPrimitive> DocumentEntity::createChildDocumentPrimitive( Variant content, const std::string &fieldName) { @@ -426,11 +435,22 @@ Rooted<DocumentPrimitive> DocumentEntity::createChildDocumentPrimitive( subInst->getManager(), subInst, std::move(content), fieldName)}; } +Rooted<DocumentPrimitive> DocumentEntity::createChildDocumentPrimitive( + Variant content, const size_t &fieldIdx) +{ + return Rooted<DocumentPrimitive>{new DocumentPrimitive( + subInst->getManager(), subInst, std::move(content), fieldIdx)}; +} + Rooted<Anchor> DocumentEntity::createChildAnchor(const std::string &fieldName) { return Rooted<Anchor>{ new Anchor(subInst->getManager(), subInst, fieldName)}; } +Rooted<Anchor> DocumentEntity::createChildAnchor(const size_t &fieldIdx) +{ + return Rooted<Anchor>{new Anchor(subInst->getManager(), subInst, fieldIdx)}; +} /* Class StructureNode */ @@ -468,6 +488,19 @@ StructureNode::StructureNode(Manager &mgr, std::string name, } } +StructureNode::StructureNode(Manager &mgr, std::string name, + Handle<Node> parent, const size_t &fieldIdx) + : Node(mgr, std::move(name), parent) +{ + if (parent->isa(&RttiTypes::StructuredEntity)) { + parent.cast<StructuredEntity>()->addStructureNode(this, fieldIdx); + } else if (parent->isa(&RttiTypes::AnnotationEntity)) { + parent.cast<AnnotationEntity>()->addStructureNode(this, fieldIdx); + } else { + throw OusiaException("The proposed parent was no DocumentEntity!"); + } +} + /* Class StructuredEntity */ StructuredEntity::StructuredEntity(Manager &mgr, Handle<Document> doc, @@ -489,8 +522,25 @@ StructuredEntity::StructuredEntity(Manager &mgr, Handle<Node> parent, bool StructuredEntity::doValidate(Logger &logger) const { + bool valid = true; + // check the parent. + if (getDescriptor() == nullptr) { + logger.error("The descriptor is not set!", *this); + valid = false; + } else if (!getDescriptor()->isa(&RttiTypes::StructuredClass)) { + logger.error("The descriptor is not a structure descriptor!", *this); + valid = false; + } else if (transparent && + !getDescriptor().cast<StructuredClass>()->isTransparent()) { + logger.error( + "The entity is marked as transparent but the descriptor " + "does not allow transparency!", + *this); + valid = false; + } + // check the validity as a StructureNode and as a DocumentEntity. - return StructureNode::doValidate(logger) & + return valid & StructureNode::doValidate(logger) & DocumentEntity::doValidate(logger); } diff --git a/src/core/model/Document.hpp b/src/core/model/Document.hpp index e314304..6903bb3 100644 --- a/src/core/model/Document.hpp +++ b/src/core/model/Document.hpp @@ -246,7 +246,7 @@ public: * FieldDescriptor in the Domain description. * @return a NodeVector of all StructuredEntities in that field. */ - const NodeVector<StructureNode> &getField(const size_t& idx ) const; + const NodeVector<StructureNode> &getField(const size_t &idx) const; /** * This adds a StructureNode to the field with the given index. @@ -259,7 +259,7 @@ public: * @param fieldIdx is the index of a field as specified in the * FieldDescriptor in the Domain description. */ - void addStructureNode(Handle<StructureNode> s, const int &fieldIdx); + void addStructureNode(Handle<StructureNode> s, const size_t &fieldIdx); /** * This adds a StructureNode to the field with the given name. * @@ -403,6 +403,23 @@ public: Variant attributes = Variant::mapType{}, const std::string &fieldName = DEFAULT_FIELD_NAME, std::string name = ""); + + /** + * This creates a new StructuredEntity as child of this DocumentEntity. + * + * @param descriptor is the StructuredClass of this StructuredEntity. + * @param attributes is a Map Variant containing attribute fillings for this + * StructuredEntity. It is empty per default. + * @param fieldIdx is the index of the field, where the newly created + * StructuredEntity shall be added to this DocumentEntity. + * @param name is some name for this StructuredEntity that may be used + * for later reference. It is empty per default. + * + * @return the newly created StructuredEntity. + */ + Rooted<StructuredEntity> createChildStructuredEntity( + Handle<StructuredClass> descriptor, const size_t &fieldIdx, + Variant attributes = Variant::mapType{}, std::string name = ""); /* * Creates a new DocumentPrimitive as child of this DocumentEntity. * @@ -416,8 +433,21 @@ public: * @return the newly created DocumentPrimitive. */ Rooted<DocumentPrimitive> createChildDocumentPrimitive( - Variant content = {}, - const std::string &fieldName = DEFAULT_FIELD_NAME); + Variant content, const std::string &fieldName = DEFAULT_FIELD_NAME); + /* + * Creates a new DocumentPrimitive as child of this DocumentEntity. + * + * @param fieldIdx is the index of the field, where the newly created + * StructuredEntity shall be added to this DocumentEntity. + * @param content is a Variant containing the content of this + * DocumentPrimitive. The Type of this Variant is + * specified at the parents Descriptor for the given + * fieldName. + * + * @return the newly created DocumentPrimitive. + */ + Rooted<DocumentPrimitive> createChildDocumentPrimitive( + Variant content, const size_t &fieldIdx); /** * Creates a new Anchor as child of this DocumentEntity. @@ -429,6 +459,16 @@ public: */ Rooted<Anchor> createChildAnchor( const std::string &fieldName = DEFAULT_FIELD_NAME); + + /** + * Creates a new Anchor as child of this DocumentEntity. + * + * @param fieldIdx is the index of the field, where the newly created + * Anchor shall be added to this DocumentEntity. + * + * @return the newly created Anchor. + */ + Rooted<Anchor> createChildAnchor(const size_t &fieldIdx); }; /** @@ -447,6 +487,11 @@ public: */ StructureNode(Manager &mgr, std::string name, Handle<Node> parent, const std::string &fieldName); + /** + * Constructor for a StructureNode in the StructureTree. + */ + StructureNode(Manager &mgr, std::string name, Handle<Node> parent, + const size_t &fieldIdx); /** * Constructor for an empty StructureNode. @@ -465,6 +510,9 @@ public: class StructuredEntity : public StructureNode, public DocumentEntity { friend Document; +private: + bool transparent = false; + protected: bool doValidate(Logger &logger) const override; @@ -494,6 +542,30 @@ public: DocumentEntity(this, descriptor, std::move(attributes)) { } + /** + * Constructor for a StructuredEntity in the Structure Tree. + * + * @param mgr is the Manager instance. + * @param parent is the parent DocumentEntity of this StructuredEntity + * in the DocumentTree. Note that this StructuredEntity + * will automatically register itself as child of this + * parent. + * @param descriptor is the StructuredClass of this StructuredEntity. + * @param fieldIdx is the index of the field in the parent DocumentEntity + * where this StructuredEntity shall be added. + * @param attributes is a Map Variant containing attribute fillings for this + * StructuredEntity. It is empty per default. + * @param name is some name for this StructuredEntity that may be used + * for later reference. It is empty per default. + */ + StructuredEntity(Manager &mgr, Handle<Node> parent, + Handle<StructuredClass> descriptor, const size_t &fieldIdx, + Variant attributes = Variant::mapType{}, + std::string name = "") + : StructureNode(mgr, std::move(name), parent, fieldIdx), + DocumentEntity(this, descriptor, std::move(attributes)) + { + } /** * Constructor for a StructuredEntity at the document root. @@ -530,6 +602,20 @@ public: Handle<StructuredClass> descriptor = nullptr, Variant attributes = Variant::mapType{}, std::string name = ""); + + /** + * Returns true if and only if this element was created using transparency/ + * if and only if this is an implicit element. + * + * @return true if and only if this element was created using transparency. + */ + bool isTransparent() const { return transparent; } + + /** + * @param trans true if and only if this element was created using + * transparency/if and only if this is an implicit element. + */ + void setTransparent(bool trans) { transparent = trans; } }; /** @@ -557,11 +643,31 @@ public: * @param fieldName is the name of the field in the parent DocumentEntity * where this DocumentPrimitive shall be added. */ - DocumentPrimitive(Manager &mgr, Handle<Node> parent, Variant content = {}, + DocumentPrimitive(Manager &mgr, Handle<Node> parent, Variant content, const std::string &fieldName = DEFAULT_FIELD_NAME) : StructureNode(mgr, "", parent, fieldName), content(content) { } + /** + * Constructor for a DocumentPrimitive. + * + * @param mgr is the Manager instance. + * @param parent is the parent DocumentEntity of this DocumentPrimitive + * in the DocumentTree. Note that this DocumentPrimitive + * will automatically register itself as child of this + * parent. + * @param content is a Variant containing the content of this + * DocumentPrimitive. The Type of this Variant is + * specified at the parents Descriptor for the given + * fieldName. + * @param fieldIdx is the index of the field in the parent DocumentEntity + * where this DocumentPrimitive shall be added. + */ + DocumentPrimitive(Manager &mgr, Handle<Node> parent, Variant content, + const size_t &fieldIdx) + : StructureNode(mgr, "", parent, fieldIdx), content(content) + { + } /** * Returns the content of this DocumentPrimitive. @@ -612,6 +718,21 @@ public: : StructureNode(mgr, "", parent, fieldName) { } + /** + * Constructor for Anchor. + * + * @param mgr is the Manager instance. + * @param parent is the parent of this Anchor in the Structure Tree (!), + * not the AnnotationEntity that references this Anchor. + * Note that this Anchor will automatically register itself + * as child of the given parent. + * @param fieldIdx is the index of the field in the parent DocumentEntity + * where this Anchor shall be added. + */ + Anchor(Manager &mgr, Handle<Node> parent, const size_t &fieldIdx) + : StructureNode(mgr, "", parent, fieldIdx) + { + } /** * Returns the AnnotationEntity this Anchor belongs to. @@ -935,4 +1056,3 @@ extern const Rtti Anchor; } #endif /* _OUSIA_MODEL_DOCUMENT_HPP_ */ - diff --git a/src/core/parser/stack/DocumentHandler.cpp b/src/core/parser/stack/DocumentHandler.cpp index 41ca8ec..49bf26b 100644 --- a/src/core/parser/stack/DocumentHandler.cpp +++ b/src/core/parser/stack/DocumentHandler.cpp @@ -51,20 +51,15 @@ void DocumentHandler::end() { scope().pop(); } /* DocumentChildHandler */ -void DocumentChildHandler::preamble(Handle<Node> parentNode, - std::string &fieldName, - DocumentEntity *&parent, bool &inField) +void DocumentChildHandler::preamble(Rooted<Node> &parentNode, size_t &fieldIdx, + DocumentEntity *&parent) { // Check if the parent in the structure tree was an explicit field // reference. - inField = parentNode->isa(&RttiTypes::DocumentField); - if (inField) { - fieldName = parentNode->getName(); + if (parentNode->isa(&RttiTypes::DocumentField)) { + fieldIdx = parentNode.cast<DocumentField>()->fieldIdx; parentNode = scope().selectOrThrow( {&RttiTypes::StructuredEntity, &RttiTypes::AnnotationEntity}); - } else { - // If it wasn't an explicit reference, we use the default field. - fieldName = DEFAULT_FIELD_NAME; } // Reference the parent entity explicitly. @@ -78,124 +73,235 @@ void DocumentChildHandler::preamble(Handle<Node> parentNode, } } -static void createPath(const NodeVector<Node> &path, DocumentEntity *&parent, - size_t p0 = 1) +void DocumentChildHandler::createPath(const NodeVector<Node> &path, + DocumentEntity *&parent, size_t p0) { - // TODO (@benjamin): These should be pushed onto the scope and poped once - // the scope is left. Otherwise stuff may not be correclty resolved. size_t S = path.size(); for (size_t p = p0; p < S; p = p + 2) { - parent = static_cast<DocumentEntity *>( - parent->createChildStructuredEntity( - path[p].cast<StructuredClass>(), Variant::mapType{}, - path[p - 1]->getName(), "").get()); + // add the field. + Rooted<DocumentField> field{new DocumentField( + manager(), scope().getLeaf(), + parent->getDescriptor()->getFieldDescriptorIndex(), true)}; + scope().push(field); + // add the transparent/implicit structure element. + Rooted<StructuredEntity> transparent = + parent->createChildStructuredEntity(path[p].cast<StructuredClass>(), + Variant::mapType{}, + path[p - 1]->getName(), ""); + transparent->setLocation(location()); + transparent->setTransparent(true); + scope().push(transparent); + parent = static_cast<DocumentEntity *>(transparent.get()); } + // add the last field. + Rooted<DocumentField> field{new DocumentField( + manager(), scope().getLeaf(), + parent->getDescriptor()->getFieldDescriptorIndex(), true)}; + scope().push(field); } -static void createPath(const std::string &firstFieldName, - const NodeVector<Node> &path, DocumentEntity *&parent) +void DocumentChildHandler::createPath(const size_t &firstFieldIdx, + const NodeVector<Node> &path, + DocumentEntity *&parent) { // Add the first element - parent = static_cast<DocumentEntity *>( - parent->createChildStructuredEntity(path[0].cast<StructuredClass>(), - Variant::mapType{}, firstFieldName, - "").get()); + Rooted<StructuredEntity> transparent = parent->createChildStructuredEntity( + path[0].cast<StructuredClass>(), firstFieldIdx); + transparent->setLocation(location()); + transparent->setTransparent(true); + scope().push(transparent); + parent = static_cast<DocumentEntity *>(transparent.get()); createPath(path, parent, 2); } bool DocumentChildHandler::start(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); + } + } + scope().setFlag(ParserFlag::POST_HEAD, true); - Rooted<Node> parentNode = scope().selectOrThrow( - {&RttiTypes::Document, &RttiTypes::StructuredEntity, - &RttiTypes::AnnotationEntity, &RttiTypes::DocumentField}); + while (true) { + Rooted<Node> parentNode = scope().getLeaf(); + + Rooted<StructuredEntity> entity; + // handle the root note specifically. + if (parentNode->isa(&RttiTypes::Document)) { + Rooted<StructuredClass> strct = scope().resolve<StructuredClass>( + Utils::split(name(), ':'), logger()); + if (strct == nullptr) { + // if we could not resolve the name, throw an exception. + throw LoggableException( + std::string("\"") + name() + "\" could not be resolved.", + location()); + } + entity = parentNode.cast<Document>()->createRootStructuredEntity( + strct, args, nameAttr); + } else { + assert(parentNode->isa(&RttiTypes::DocumentField)); - std::string fieldName; - DocumentEntity *parent; - bool inField; - - preamble(parentNode, fieldName, parent, inField); - - // Try to find a FieldDescriptor for the given tag if we are not in a - // field already. This does _not_ try to construct transparent paths - // in between. - if (!inField && parent != nullptr && - parent->getDescriptor()->hasField(name())) { - Rooted<DocumentField> field{ - new DocumentField(parentNode->getManager(), name(), parentNode)}; - field->setLocation(location()); - scope().push(field); - return true; - } + size_t fieldIdx; + DocumentEntity *parent; - // Otherwise create a new StructuredEntity - // TODO: Consider Anchors and AnnotationEntities - Rooted<StructuredClass> strct = - scope().resolve<StructuredClass>(Utils::split(name(), ':'), logger()); - if (strct == nullptr) { - // if we could not resolve the name, throw an exception. - throw LoggableException( - std::string("\"") + name() + "\" could not be resolved.", - location()); - } + preamble(parentNode, fieldIdx, parent); - std::string name; - auto it = args.find("name"); - if (it != args.end()) { - name = it->second.asString(); - args.erase(it); - } + // TODO: REMOVE + std::string thisName = name(); + std::string parentClassName; + if (parent != nullptr) { + parentClassName = parent->getDescriptor()->getName(); + } - Rooted<StructuredEntity> entity; - if (parentNode->isa(&RttiTypes::Document)) { - entity = parentNode.cast<Document>()->createRootStructuredEntity( - strct, args, name); - } else { - // calculate a path if transparent entities are needed in between. - std::string lastFieldName = fieldName; - if (inField) { - Rooted<FieldDescriptor> field = - parent->getDescriptor()->getFieldDescriptor(fieldName); - auto pathRes = - field.cast<FieldDescriptor>()->pathTo(strct, logger()); - if (!pathRes.second) { + /* + * Try to find a FieldDescriptor for the given tag if we are not in + * a field already. This does _not_ try to construct transparent + * paths in between. + */ + { + ssize_t newFieldIdx = + parent->getDescriptor()->getFieldDescriptorIndex(name()); + if (newFieldIdx != -1) { + Rooted<DocumentField> field{new DocumentField( + manager(), parentNode, newFieldIdx, false)}; + field->setLocation(location()); + scope().push(field); + isExplicitField = true; + return true; + } + } + + // Otherwise create a new StructuredEntity + // TODO: Consider Anchors and AnnotationEntities + Rooted<StructuredClass> strct = scope().resolve<StructuredClass>( + Utils::split(name(), ':'), logger()); + if (strct == nullptr) { + // if we could not resolve the name, throw an exception. throw LoggableException( - std::string("An instance of \"") + strct->getName() + - "\" is not allowed as child of field \"" + fieldName + - "\"", + std::string("\"") + name() + "\" could not be resolved.", location()); } - if (!pathRes.first.empty()) { - createPath(fieldName, pathRes.first, parent); - lastFieldName = DEFAULT_FIELD_NAME; - } - } else { - auto path = parent->getDescriptor()->pathTo(strct, logger()); - if (path.empty()) { + + // calculate a path if transparent entities are needed in between. + Rooted<FieldDescriptor> field = + parent->getDescriptor()->getFieldDescriptors()[fieldIdx]; + size_t lastFieldIdx = fieldIdx; + auto pathRes = field->pathTo(strct, logger()); + if (!pathRes.second) { + 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(); + // pop the implicit element. + scope().pop(); + continue; + } throw LoggableException( std::string("An instance of \"") + strct->getName() + - "\" is not allowed as child of an instance of \"" + + "\" is not allowed as child of field \"" + + field->getName() + "\" of descriptor \"" + parent->getDescriptor()->getName() + "\"", location()); } - - // create all transparent entities until the last field. - createPath(path, parent); - if (path.size() > 1) { - lastFieldName = DEFAULT_FIELD_NAME; + if (!pathRes.first.empty()) { + createPath(lastFieldIdx, pathRes.first, parent); + lastFieldIdx = + parent->getDescriptor()->getFieldDescriptorIndex(); } + // create the entity for the new element at last. + entity = parent->createChildStructuredEntity(strct, lastFieldIdx, + args, nameAttr); } - // create the entity for the new element at last. - entity = parent->createChildStructuredEntity(strct, args, lastFieldName, - name); + entity->setLocation(location()); + scope().push(entity); + return true; } - entity->setLocation(location()); - scope().push(entity); +} + +void DocumentChildHandler::end() +{ + // in case of explicit fields we do not want to pop something from the + // stack. + if (isExplicitField) { + return; + } + // pop the "main" element. + scope().pop(); +} + +bool DocumentChildHandler::fieldStart(bool &isDefault, size_t fieldIdx) +{ + if (isExplicitField) { + // In case of explicit fields we do not want to create another field. + isDefault = true; + return fieldIdx == 0; + } + Rooted<Node> parentNode = scope().getLeaf(); + assert(parentNode->isa(&RttiTypes::StructuredEntity) || + parentNode->isa(&RttiTypes::AnnotationEntity)); + size_t dummy; + DocumentEntity *parent; + + preamble(parentNode, dummy, parent); + + NodeVector<FieldDescriptor> fields = + parent->getDescriptor()->getFieldDescriptors(); + + if (isDefault) { + fieldIdx = fields.size() - 1; + } else { + if (fieldIdx >= fields.size()) { + return false; + } + isDefault = fieldIdx == fields.size() - 1; + } + // push the field on the stack. + Rooted<DocumentField> field{ + new DocumentField(manager(), parentNode, fieldIdx, false)}; + field->setLocation(location()); + scope().push(field); return true; } -void DocumentChildHandler::end() { scope().pop(); } +void DocumentChildHandler::fieldEnd() +{ + assert(scope().getLeaf()->isa(&RttiTypes::DocumentField)); + + // pop the field from the stack. + scope().pop(); + + // pop all remaining transparent elements. + while (scope().getLeaf()->isa(&RttiTypes::StructuredEntity) && + scope().getLeaf().cast<StructuredEntity>()->isTransparent()) { + // pop the transparent element. + scope().pop(); + // pop the transparent field. + scope().pop(); + } +} + +bool DocumentChildHandler::annotationStart(const Variant &className, + Variant::mapType &args) +{ + // TODO: Implement + return false; +} + +bool DocumentChildHandler::annotationEnd(const Variant &className, + const Variant &elementName) +{ + // TODO: Implement + return false; +} bool DocumentChildHandler::convertData(Handle<FieldDescriptor> field, Variant &data, Logger &logger) @@ -226,71 +332,40 @@ bool DocumentChildHandler::convertData(Handle<FieldDescriptor> field, bool DocumentChildHandler::data(Variant &data) { - Rooted<Node> parentNode = scope().selectOrThrow( - {&RttiTypes::StructuredEntity, &RttiTypes::AnnotationEntity, - &RttiTypes::DocumentField}); - - std::string fieldName; - DocumentEntity *strctParent; - bool inField; - - preamble(parentNode, fieldName, strctParent, inField); - - Rooted<Descriptor> desc = strctParent->getDescriptor(); - // The parent from which we need to connect to the primitive content. - Rooted<Node> parentClass; - - // We distinguish two cases here: One for fields that are given. - if (inField) { - // Retrieve the actual FieldDescriptor - Rooted<FieldDescriptor> field = desc->getFieldDescriptor(fieldName); - if (field == nullptr) { - logger().error( - std::string("Can't handle data because no field with name \"") + - fieldName + "\" exists in descriptor\"" + desc->getName() + - "\".", - location()); + Rooted<Node> parentField = scope().getLeaf(); + assert(parentField->isa(&RttiTypes::DocumentField)); + + size_t fieldIdx; + DocumentEntity *parent; + + preamble(parentField, fieldIdx, parent); + + Rooted<Descriptor> desc = parent->getDescriptor(); + + // Retrieve the actual FieldDescriptor + Rooted<FieldDescriptor> field = desc->getFieldDescriptors()[fieldIdx]; + // If it is a primitive field directly, try to parse the content. + if (field->isPrimitive()) { + // Add it as primitive content. + if (!convertData(field, data, logger())) { return false; } - // If it is a primitive field directly, try to parse the content. - if (field->isPrimitive()) { - // Add it as primitive content. - if (!convertData(field, data, logger())) { - return false; - } - strctParent->createChildDocumentPrimitive(data, fieldName); - return true; - } - // If it is not primitive we need to connect via transparent elements - // and default fields. - parentClass = field; - } else { - // In case of default fields we need to construct via default fields - // and maybe transparent elements. - parentClass = desc; + parent->createChildDocumentPrimitive(data, fieldIdx); + return true; } // Search through all permitted default fields of the parent class that // allow primitive content at this point and could be constructed via // transparent intermediate entities. - - // Retrieve all default fields at this point, either from the field - // descriptor or the structured class - NodeVector<FieldDescriptor> defaultFields; - if (inField) { - defaultFields = parentClass.cast<FieldDescriptor>()->getDefaultFields(); - } else { - defaultFields = parentClass.cast<StructuredClass>()->getDefaultFields(); - } - + NodeVector<FieldDescriptor> defaultFields = field->getDefaultFields(); // Try to parse the data using the type specified by the respective field. // If that does not work we proceed to the next possible field. std::vector<LoggerFork> forks; - for (auto field : defaultFields) { + for (auto primitiveField : defaultFields) { // Then try to parse the content using the type specification. forks.emplace_back(logger().fork()); - if (!convertData(field, data, forks.back())) { + if (!convertData(primitiveField, data, forks.back())) { continue; } @@ -298,18 +373,12 @@ bool DocumentChildHandler::data(Variant &data) forks.back().commit(); // Construct the necessary path - if (inField) { - NodeVector<Node> path = - parentClass.cast<FieldDescriptor>()->pathTo(field, logger()); - createPath(fieldName, path, strctParent); - } else { - auto pathRes = desc->pathTo(field, logger()); - assert(pathRes.second); - createPath(pathRes.first, strctParent); - } + NodeVector<Node> path = field->pathTo(primitiveField, logger()); + // TODO: Create methods with indices instead of names. + createPath(fieldIdx, path, parent); // Then create the primitive element - strctParent->createChildDocumentPrimitive(data); + parent->createChildDocumentPrimitive(data); return true; } diff --git a/src/core/parser/stack/DocumentHandler.hpp b/src/core/parser/stack/DocumentHandler.hpp index 2c474f9..5953e3a 100644 --- a/src/core/parser/stack/DocumentHandler.hpp +++ b/src/core/parser/stack/DocumentHandler.hpp @@ -76,29 +76,74 @@ public: */ class DocumentField : public Node { public: - using Node::Node; + const size_t fieldIdx; + const bool transparent; + + DocumentField(Manager &mgr, Handle<Node> parent, size_t fieldIdx, + bool transparent) + : Node(mgr, parent), fieldIdx(fieldIdx), transparent(transparent) + { + } }; /** * The DocumentChildHandler class performs the actual parsing of the user * defined elements in an Ousía document. */ -class DocumentChildHandler : public StaticHandler { +class DocumentChildHandler : public Handler { private: + bool isExplicitField = false; + /** - * Code shared by both the start() and the end() method. Checks whether the - * parser currently is in a field and returns the name of this field. + * Code shared by both the start(), fieldStart() and the data() method. + * Checks whether the parser currently is in a field and returns the name + * of this field. * * @param parentNode is the next possible parent node (a document, * a structured entity, an annotation entity or a field). - * @param fieldName is an output parameter to which the name of the current + * @param fieldIdx is an output parameter to which the index of the current * field is written (or unchanged if we're not in a field). * @param parent is an output parameter to which the parent document entity * will be written. - * @param inField is set to true if we actually are in a field. */ - void preamble(Handle<Node> parentNode, std::string &fieldName, - DocumentEntity *&parent, bool &inField); + void preamble(Rooted<Node> &parentNode, size_t &fieldIdx, + DocumentEntity *&parent); + + /** + * Creates transparent elements that are stored in the given path. + * + * @param path a NodeVector of alternating FieldDescriptors and + * StructuredClasses. For each of the StructuredClasses at + * index p an instance is created and added to the field at + * index p-1 of the previously created instance of the + * StructuredClass at index p-2. + * @param parent is the parent DocumentEntity for the first transparent + * element. This will be reset for each created transparent + * element. + * @param p0 is the index of the path vector of the first + * StructuredClass for which an instance shall be created. + * This is 1 per default. + */ + void createPath(const NodeVector<Node> &path, DocumentEntity *&parent, + size_t p0 = 1); + + /** + * Creates transparent elements that are stored in the given path. + * + * @param fieldIdx is the index of the field for which the first instance + * shall be added. + * @param path a NodeVector of alternating FieldDescriptors and + * StructuredClasses. For each of the StructuredClasses at + * index p an instance is created and added to the field at + * index p-1 of the previously created instance of the + * StructuredClass at index p-2. The first element has + * to be a StructuredClass. + * @param parent is the parent DocumentEntity for the first transparent + * element. This will be reset for each created transparent + * element. + */ + void createPath(const size_t &fieldIdx, const NodeVector<Node> &path, + DocumentEntity *&parent); /** * Tries to convert the given data to the type that is specified in the @@ -116,12 +161,22 @@ private: Logger &logger); public: - using StaticHandler::StaticHandler; + using Handler::Handler; bool start(Variant::mapType &args) override; void end() override; bool data(Variant &data) override; + bool fieldStart(bool &isDefault, size_t fieldIdx) override; + + void fieldEnd() override; + + bool annotationStart(const Variant &className, + Variant::mapType &args) override; + + bool annotationEnd(const Variant &className, + const Variant &elementName) override; + /** * Creates a new instance of the DocumentChildHandler. * @@ -146,7 +201,6 @@ extern const State Document; */ extern const State DocumentChild; } - } namespace RttiTypes { @@ -155,8 +209,6 @@ namespace RttiTypes { */ extern const Rtti DocumentField; } - } -#endif /* _OUSIA_PARSER_STACK_DOCUMENT_HANDLER_HPP_ */ - +#endif /* _OUSIA_PARSER_STACK_DOCUMENT_HANDLER_HPP_ */
\ No newline at end of file |