diff options
Diffstat (limited to 'src/core/parser/stack/DocumentHandler.cpp')
-rw-r--r-- | src/core/parser/stack/DocumentHandler.cpp | 213 |
1 files changed, 132 insertions, 81 deletions
diff --git a/src/core/parser/stack/DocumentHandler.cpp b/src/core/parser/stack/DocumentHandler.cpp index 9fedabb..d514701 100644 --- a/src/core/parser/stack/DocumentHandler.cpp +++ b/src/core/parser/stack/DocumentHandler.cpp @@ -78,13 +78,13 @@ void DocumentChildHandler::preamble(Handle<Node> parentNode, } } -void DocumentChildHandler::createPath(const NodeVector<Node> &path, - DocumentEntity *&parent) +static void createPath(const NodeVector<Node> &path, DocumentEntity *&parent, + size_t p0 = 1) { // 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 = 1; p < S; p = p + 2) { + for (size_t p = p0; p < S; p = p + 2) { parent = static_cast<DocumentEntity *>( parent->createChildStructuredEntity( path[p].cast<StructuredClass>(), Variant::mapType{}, @@ -92,6 +92,18 @@ void DocumentChildHandler::createPath(const NodeVector<Node> &path, } } +static void createPath(const std::string &firstFieldName, + const NodeVector<Node> &path, DocumentEntity *&parent) +{ + // Add the first element + parent = static_cast<DocumentEntity *>( + parent->createChildStructuredEntity(path[0].cast<StructuredClass>(), + Variant::mapType{}, firstFieldName, + "").get()); + + createPath(path, parent, 2); +} + bool DocumentChildHandler::start(Variant::mapType &args) { scope().setFlag(ParserFlag::POST_HEAD, true); @@ -111,7 +123,7 @@ bool DocumentChildHandler::start(Variant::mapType &args) if (!inField && parent != nullptr && parent->getDescriptor()->hasField(name())) { Rooted<DocumentField> field{ - new DocumentField(parentNode->getManager(), fieldName, parentNode)}; + new DocumentField(parentNode->getManager(), name(), parentNode)}; field->setLocation(location()); scope().push(field); return true; @@ -141,19 +153,42 @@ bool DocumentChildHandler::start(Variant::mapType &args) strct, args, name); } else { // calculate a path if transparent entities are needed in between. - auto path = parent->getDescriptor()->pathTo(strct, logger()); - if (path.empty()) { - throw LoggableException( - std::string("An instance of \"") + strct->getName() + - "\" is not allowed as child of an instance of \"" + - parent->getDescriptor()->getName() + "\"", - location()); - } + std::string lastFieldName = fieldName; + if (inField) { + Rooted<FieldDescriptor> field = + parent->getDescriptor()->getFieldDescriptor(fieldName); + auto pathRes = + field.cast<FieldDescriptor>()->pathTo(strct, logger()); + if (!pathRes.second) { + throw LoggableException( + std::string("An instance of \"") + strct->getName() + + "\" is not allowed as child of field \"" + fieldName + + "\"", + 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()) { + throw LoggableException( + std::string("An instance of \"") + strct->getName() + + "\" is not allowed as child of an instance of \"" + + parent->getDescriptor()->getName() + "\"", + location()); + } - // create all transparent entities until the last field. - createPath(path, parent); - entity = - parent->createChildStructuredEntity(strct, args, fieldName, name); + // create all transparent entities until the last field. + createPath(path, parent); + if (path.size() > 1) { + lastFieldName = DEFAULT_FIELD_NAME; + } + } + // create the entity for the new element at last. + entity = parent->createChildStructuredEntity(strct, args, lastFieldName, + name); } entity->setLocation(location()); scope().push(entity); @@ -196,15 +231,17 @@ bool DocumentChildHandler::data(Variant &data) &RttiTypes::DocumentField}); std::string fieldName; - DocumentEntity *parent; + DocumentEntity *strctParent; bool inField; - preamble(parentNode, fieldName, parent, inField); + preamble(parentNode, fieldName, strctParent, inField); - Rooted<Descriptor> desc = parent->getDescriptor(); + 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 (fieldName != DEFAULT_FIELD_NAME) { + if (inField) { // Retrieve the actual FieldDescriptor Rooted<FieldDescriptor> field = desc->getFieldDescriptor(fieldName); if (field == nullptr) { @@ -215,81 +252,95 @@ bool DocumentChildHandler::data(Variant &data) location()); return false; } - // 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()); - 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; + } - // Try to convert the data variable to the correct format, abort if this - // does not work - 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; + } - // Add it as primitive content - parent->createChildDocumentPrimitive(data, fieldName); - 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 { - // 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. - NodeVector<FieldDescriptor> fields = desc->getDefaultFields(); - std::vector<LoggerFork> forks; - for (auto field : fields) { - // Then try to parse the content using the type specification - forks.emplace_back(logger().fork()); - - // Try to convert the data variable to the correct format, abort if - // this does not work - if (!convertData(field, data, forks.back())) { - return false; - } + defaultFields = parentClass.cast<StructuredClass>()->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) { + // Then try to parse the content using the type specification. + forks.emplace_back(logger().fork()); + if (!convertData(field, data, forks.back())) { + continue; + } - // Show possible warnings that were emitted by this type conversion - forks.back().commit(); + // The conversion worked, commit any possible warnings + forks.back().commit(); - // If that worked, construct the necessary path + // 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); - NodeVector<Node> path = pathRes.first; - createPath(path, parent); - - // Then create the primitive element - parent->createChildDocumentPrimitive(data, fieldName); - return true; - } - 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(); + createPath(pathRes.first, strctParent); } - return false; + + // Then create the primitive element + strctParent->createChildDocumentPrimitive(data); + return true; } - return true; + + // No field was found that might take the data -- dump the error messages + // from the loggers + logger().error("Could not read data with any of the possible fields:", + SourceLocation{}, MessageMode::NO_CONTEXT); + size_t f = 0; + for (auto field : defaultFields) { + logger().note(std::string("Field ") + Utils::join(field->path(), ".") + + std::string(":"), + SourceLocation{}, MessageMode::NO_CONTEXT); + forks[f].commit(); + f++; + } + return false; } namespace States { const State Document = StateBuilder() - .parent(&None) - .createdNodeType(&RttiTypes::Document) - .elementHandler(DocumentHandler::create) - .arguments({Argument::String("name", "")}); - -const State DocumentChild = - StateBuilder() - .parents({&Document, &DocumentChild}) - .createdNodeTypes({&RttiTypes::StructureNode, - &RttiTypes::AnnotationEntity, - &RttiTypes::DocumentField}) - .elementHandler(DocumentChildHandler::create); + .parent(&None) + .createdNodeType(&RttiTypes::Document) + .elementHandler(DocumentHandler::create) + .arguments({Argument::String("name", "")}); + +const State DocumentChild = StateBuilder() + .parents({&Document, &DocumentChild}) + .createdNodeTypes({&RttiTypes::StructureNode, + &RttiTypes::AnnotationEntity, + &RttiTypes::DocumentField}) + .elementHandler(DocumentChildHandler::create); } } |