From 0d8da1277274ef1b79b48df47e4dbc070f543d33 Mon Sep 17 00:00:00 2001 From: Benjamin Paassen Date: Sun, 15 Feb 2015 18:17:31 +0100 Subject: added support for transparent elements between explicit fields and primitive content. --- src/core/parser/stack/DocumentHandler.cpp | 127 +++++++++++++++++++----------- 1 file changed, 80 insertions(+), 47 deletions(-) (limited to 'src/core/parser/stack/DocumentHandler.cpp') diff --git a/src/core/parser/stack/DocumentHandler.cpp b/src/core/parser/stack/DocumentHandler.cpp index ba7430d..01ee594 100644 --- a/src/core/parser/stack/DocumentHandler.cpp +++ b/src/core/parser/stack/DocumentHandler.cpp @@ -70,8 +70,25 @@ void DocumentChildHandler::preamble(Handle parentNode, } } -void DocumentChildHandler::createPath(const NodeVector &path, - DocumentEntity *&parent) +static void createPath(const std::string &firstFieldName, + const NodeVector &path, DocumentEntity *&parent) +{ + // add the first element + parent = static_cast( + parent->createChildStructuredEntity(path[0].cast(), + Variant::mapType{}, firstFieldName, + "").get()); + + size_t S = path.size(); + for (size_t p = 2; p < S; p = p + 2) { + parent = static_cast( + parent->createChildStructuredEntity( + path[p].cast(), Variant::mapType{}, + path[p - 1]->getName(), "").get()); + } +} + +static void createPath(const NodeVector &path, DocumentEntity *&parent) { size_t S = path.size(); for (size_t p = 1; p < S; p = p + 2) { @@ -101,7 +118,7 @@ void DocumentChildHandler::start(Variant::mapType &args) if (!inField && parent != nullptr && parent->getDescriptor()->hasField(name())) { Rooted field{ - new DocumentField(parentNode->getManager(), fieldName, parentNode)}; + new DocumentField(parentNode->getManager(), name(), parentNode)}; field->setLocation(location()); scope().push(field); return; @@ -174,12 +191,14 @@ void DocumentChildHandler::data(const std::string &data, int fieldIdx) &RttiTypes::DocumentField}); std::string fieldName; - DocumentEntity *parent; + DocumentEntity *strctParent; bool inField; - preamble(parentNode, fieldName, parent, inField); + preamble(parentNode, fieldName, strctParent, inField); - Rooted desc = parent->getDescriptor(); + Rooted desc = strctParent->getDescriptor(); + // The parent from which we need to connect to the primitive content. + Rooted parentClass; /* * We distinguish two cases here: One for fields that are given. */ @@ -194,54 +213,68 @@ void DocumentChildHandler::data(const std::string &data, int fieldIdx) location()); return; } - // if it is not primitive at all, we can't parse the content. - if (!field->isPrimitive()) { - logger().error(std::string("Can't handle data because field \"") + - fieldName + "\" of descriptor \"" + - desc->getName() + "\" is not primitive!", - location()); + // if it is a primitive field directly, try to parse the content. + if (field->isPrimitive()) { + auto res = convertData(field, logger(), data); + // add it as primitive content. + if (res.first) { + strctParent->createChildDocumentPrimitive(res.second, + fieldName); + } return; } + // 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; + } + /* + * 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. + * We then 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. + */ + // retrieve all default fields at this point. + NodeVector defaultFields; + if (parentClass->isa(&RttiTypes::FieldDescriptor)) { + defaultFields = parentClass.cast()->getDefaultFields(); + } else { + defaultFields = parentClass.cast()->getDefaultFields(); + } + std::vector forks; + for (auto field : defaultFields) { // then try to parse the content using the type specification. - auto res = convertData(field, logger(), data); - // add it as primitive content. + forks.emplace_back(logger().fork()); + auto res = convertData(field, forks.back(), data); if (res.first) { - parent->createChildDocumentPrimitive(res.second, fieldName); - } - } else { - /* - * The second case is for primitive fields. Here we search through - * all FieldDescriptors that allow primitive content at this point - * and could be constructed via transparent intermediate entities. - * We then 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. - */ - // retrieve all fields. - NodeVector fields = desc->getDefaultFields(); - std::vector forks; - for (auto field : fields) { - // then try to parse the content using the type specification. - forks.emplace_back(logger().fork()); - auto res = convertData(field, forks.back(), data); - if (res.first) { - forks.back().commit(); - // if that worked, construct the necessary path. + forks.back().commit(); + // if that worked, construct the necessary path. + if (parentClass->isa(&RttiTypes::FieldDescriptor)) { + NodeVector path = + parentClass.cast()->pathTo(field, + logger()); + createPath(fieldName, path, strctParent); + } else { auto pathRes = desc->pathTo(field, logger()); assert(pathRes.second); - NodeVector path = pathRes.first; - createPath(path, parent); - // then create the primitive element. - parent->createChildDocumentPrimitive(res.second, fieldName); - return; + createPath(pathRes.first, strctParent); } + // then create the primitive element. + strctParent->createChildDocumentPrimitive(res.second); + return; } - logger().error("Could not read data with any of the possible fields:"); - for (size_t f = 0; f < fields.size(); f++) { - logger().note(Utils::join(fields[f]->path(), ".") + ":", - SourceLocation{}, MessageMode::NO_CONTEXT); - forks[f].commit(); - } + } + logger().error("Could not read data with any of the possible fields:"); + size_t f = 0; + for (auto field : defaultFields) { + logger().note(Utils::join(field->path(), ".") + ":", SourceLocation{}, + MessageMode::NO_CONTEXT); + forks[f].commit(); + f++; } } @@ -249,4 +282,4 @@ namespace RttiTypes { const Rtti DocumentField = RttiBuilder("DocumentField").parent(&Node); } -} +} \ No newline at end of file -- cgit v1.2.3