summaryrefslogtreecommitdiff
path: root/src/core
diff options
context:
space:
mode:
authorAndreas Stöckel <astoecke@techfak.uni-bielefeld.de>2015-02-16 18:58:12 +0100
committerAndreas Stöckel <andreas@somweyr.de>2015-02-16 18:58:12 +0100
commit75eea3bdd846a34c69be3d09f41ff4fae706628e (patch)
treeaf42dbf2fd9ea87884cd500367c4017293609863 /src/core
parent67f5572b423345a6e243516070a335a521459384 (diff)
parentd4e835e5eaa40e5d7bfe2a51f03505bc27ddc8f7 (diff)
Merge branch 'master' of ssh://somweyr.de/var/local/git/ousia
Diffstat (limited to 'src/core')
-rw-r--r--src/core/model/Document.cpp54
-rw-r--r--src/core/model/Document.hpp132
-rw-r--r--src/core/parser/stack/DocumentHandler.cpp381
-rw-r--r--src/core/parser/stack/DocumentHandler.hpp78
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