summaryrefslogtreecommitdiff
path: root/src/core/parser/stack/DocumentHandler.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/parser/stack/DocumentHandler.cpp')
-rw-r--r--src/core/parser/stack/DocumentHandler.cpp213
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);
}
}