diff options
Diffstat (limited to 'src/plugins')
-rw-r--r-- | src/plugins/xml/XmlParser.cpp | 218 |
1 files changed, 192 insertions, 26 deletions
diff --git a/src/plugins/xml/XmlParser.cpp b/src/plugins/xml/XmlParser.cpp index c2e89ec..7b4b1b3 100644 --- a/src/plugins/xml/XmlParser.cpp +++ b/src/plugins/xml/XmlParser.cpp @@ -75,6 +75,128 @@ public: } }; +class DocumentField : public Node { +public: + DocumentField(Manager &mgr, std::string name, Handle<Node> parent) + : Node(mgr, name, parent) + { + } +}; + +namespace RttiTypes { +const Rtti DocumentField = + RttiBuilder<ousia::DocumentField>("DocumentField").parent(&Node); +} + +class DocumentChildHandler : public Handler { +public: + using Handler::Handler; + + void preamble(Handle<Node> parentNode, std::string &fieldName, + DocumentEntity *&parent, bool &inField) + { + // check if the parent in the structure tree was an explicit field + // reference. + inField = parentNode->isa(RttiTypes::DocumentField); + if (inField) { + fieldName = parentNode->getName(); + 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. + parent = nullptr; + if (parentNode->isa(RttiTypes::StructuredEntity)) { + parent = static_cast<DocumentEntity *>( + parentNode.cast<StructuredEntity>().get()); + } else if (parentNode->isa(RttiTypes::AnnotationEntity)) { + parent = static_cast<DocumentEntity *>( + parentNode.cast<AnnotationEntity>().get()); + } + } + + void start(Variant::mapType &args) override + { + scope().setFlag(ParserFlag::POST_HEAD, true); + Rooted<Node> parentNode = scope().selectOrThrow( + {&RttiTypes::Document, &RttiTypes::StructuredEntity, + &RttiTypes::AnnotationEntity, &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. + if (!inField && parent != nullptr && parent->hasField(fieldName)) { + Rooted<DocumentField> field{new DocumentField( + parentNode->getManager(), fieldName, parentNode)}; + field->setLocation(location()); + scope().push(field); + return; + } + + // 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()); + } + std::string name; + auto it = args.find("name"); + if (it != args.end()) { + name = it->second.asString(); + args.erase(it); + } + Rooted<StructuredEntity> entity; + if (parentNode->isa(RttiTypes::Document)) { + entity = parentNode.cast<Document>()->createRootStructuredEntity( + strct, args, name); + } else { + entity = parent->createChildStructuredEntity(strct, args, fieldName, + name); + } + entity->setLocation(location()); + scope().push(entity); + } + + void end() override { scope().pop(); } + + void data(const std::string &data, int field) override + { + // Rooted<Node> parentNode = scope().selectOrThrow( + // { &RttiTypes::StructuredEntity, + // &RttiTypes::AnnotationEntity, &RttiTypes::DocumentField}); + + // std::string fieldName; + // DocumentEntity *parent; + // bool inField; + // + // preamble(parentNode, fieldName, parent, inField); + // + // // retrieve the correct FieldDescriptor. + // + // + // CharReader reader{data, location().getSourceId(), + // location().getStart()}; + // auto res = VariantReader::parseGeneric(reader, logger(), + // std::unordered_set<char>{}); + } + + static Handler *create(const HandlerData &handlerData) + { + return new DocumentChildHandler{handlerData}; + } +}; + class TypesystemHandler : public Handler { public: using Handler::Handler; @@ -315,8 +437,7 @@ public: Rooted<StructuredClass> structuredClass = domain->createStructuredClass( args["name"].asString(), args["cardinality"].asCardinality(), - nullptr, nullptr, args["transparent"].asBool(), - args["isRoot"].asBool()); + nullptr, args["transparent"].asBool(), args["isRoot"].asBool()); structuredClass->setLocation(location()); const std::string &isa = args["isa"].asString(); @@ -327,7 +448,7 @@ public: Logger &logger) { if (superclass != nullptr) { structuredClass.cast<StructuredClass>()->setSuperclass( - superclass.cast<StructuredClass>()); + superclass.cast<StructuredClass>(), logger); } }); } @@ -354,7 +475,7 @@ public: Rooted<Domain> domain = scope().selectOrThrow<Domain>(); Rooted<AnnotationClass> annotationClass = - domain->createAnnotationClass(args["name"].asString(), nullptr); + domain->createAnnotationClass(args["name"].asString()); annotationClass->setLocation(location()); scope().push(annotationClass); @@ -368,6 +489,29 @@ public: } }; +class DomainAttributesHandler : public Handler { +public: + using Handler::Handler; + + void start(Variant::mapType &args) override + { + // Fetch the current typesystem and create the struct node + Rooted<Descriptor> parent = scope().selectOrThrow<Descriptor>(); + + Rooted<StructType> attrDesc = parent->getAttributesDescriptor(); + attrDesc->setLocation(location()); + + scope().push(attrDesc); + } + + void end() override { scope().pop(); } + + static Handler *create(const HandlerData &handlerData) + { + return new DomainAttributesHandler{handlerData}; + } +}; + class DomainFieldHandler : public Handler { public: using Handler::Handler; @@ -486,17 +630,17 @@ public: } }; -class DummyParentNode : public Node { +class DomainParent : public Node { public: - DummyParentNode(Manager &mgr, std::string name, Handle<Node> parent) + DomainParent(Manager &mgr, std::string name, Handle<Node> parent) : Node(mgr, name, parent) { } }; namespace RttiTypes { -const Rtti DummyParentNode = - RttiBuilder<ousia::DummyParentNode>("DummyParentNode").parent(&Node); +const Rtti DomainParent = + RttiBuilder<ousia::DomainParent>("DomainParent").parent(&Node); } class DomainParentHandler : public Handler { @@ -508,11 +652,10 @@ public: Rooted<StructuredClass> strct = scope().selectOrThrow<StructuredClass>(); - // TODO: Is there a better way for this? - Rooted<DummyParentNode> dummy{new DummyParentNode( + Rooted<DomainParent> parent{new DomainParent( strct->getManager(), args["name"].asString(), strct)}; - dummy->setLocation(location()); - scope().push(dummy); + parent->setLocation(location()); + scope().push(parent); } void end() override { scope().pop(); } @@ -529,8 +672,8 @@ public: void start(Variant::mapType &args) override { - Rooted<DummyParentNode> dummy = - scope().selectOrThrow<DummyParentNode>(); + Rooted<DomainParent> parentNameNode = + scope().selectOrThrow<DomainParent>(); FieldDescriptor::FieldType type; if (args["isSubtree"].asBool()) { type = FieldDescriptor::FieldType::SUBTREE; @@ -541,14 +684,14 @@ public: const std::string &name = args["name"].asString(); const bool optional = args["optional"].asBool(); Rooted<StructuredClass> strct = - dummy->getParent().cast<StructuredClass>(); + parentNameNode->getParent().cast<StructuredClass>(); // resolve the parent, create the declared field and add the declared // StructuredClass as child to it. scope().resolve<Descriptor>( - dummy->getName(), strct, logger(), + parentNameNode->getName(), strct, logger(), [type, name, optional](Handle<Node> parent, Handle<Node> strct, - Logger &logger) { + Logger &logger) { if (parent != nullptr) { Rooted<FieldDescriptor> field = parent.cast<Descriptor>()->createFieldDescriptor( @@ -572,20 +715,20 @@ public: void start(Variant::mapType &args) override { - Rooted<DummyParentNode> dummy = - scope().selectOrThrow<DummyParentNode>(); + Rooted<DomainParent> parentNameNode = + scope().selectOrThrow<DomainParent>(); const std::string &name = args["name"].asString(); Rooted<StructuredClass> strct = - dummy->getParent().cast<StructuredClass>(); + parentNameNode->getParent().cast<StructuredClass>(); auto loc = location(); // resolve the parent, get the referenced field and add the declared // StructuredClass as child to it. - scope().resolve<Descriptor>(dummy->getName(), strct, logger(), + scope().resolve<Descriptor>(parentNameNode->getName(), strct, logger(), [name, loc](Handle<Node> parent, - Handle<Node> strct, - Logger &logger) { + Handle<Node> strct, + Logger &logger) { if (parent != nullptr) { auto res = parent.cast<Descriptor>()->resolve( RttiTypes::FieldDescriptor, name); @@ -719,6 +862,14 @@ static const ParserState Document = .elementHandler(DocumentHandler::create) .arguments({Argument::String("name", "")}); +static const ParserState DocumentChild = + ParserStateBuilder() + .parent(&Document) + .createdNodeTypes({&RttiTypes::StructureNode, + &RttiTypes::AnnotationEntity, + &RttiTypes::DocumentField}) + .elementHandler(DocumentChildHandler::create); + /* Domain states */ static const ParserState Domain = ParserStateBuilder() .parents({&None, &Document}) @@ -736,7 +887,6 @@ static const ParserState DomainStruct = Argument::Bool("isRoot", false), Argument::Bool("transparent", false), Argument::String("isa", "")}); -// TODO: What about attributes? static const ParserState DomainAnnotation = ParserStateBuilder() @@ -744,7 +894,20 @@ static const ParserState DomainAnnotation = .createdNodeType(&RttiTypes::AnnotationClass) .elementHandler(DomainAnnotationHandler::create) .arguments({Argument::String("name")}); -// TODO: What about attributes? + +static const ParserState DomainAttributes = + ParserStateBuilder() + .parents({&DomainStruct, &DomainAnnotation}) + .createdNodeType(&RttiTypes::StructType) + .elementHandler(DomainAttributesHandler::create) + .arguments({}); + +static const ParserState DomainAttribute = + ParserStateBuilder() + .parent(&DomainAttributes) + .elementHandler(TypesystemStructFieldHandler::create) + .arguments({Argument::String("name"), Argument::String("type"), + Argument::Any("default", Variant::fromObject(nullptr))}); static const ParserState DomainField = ParserStateBuilder() @@ -780,7 +943,7 @@ static const ParserState DomainStructChild = static const ParserState DomainStructParent = ParserStateBuilder() .parent(&DomainStruct) - .createdNodeType(&RttiTypes::DummyParentNode) + .createdNodeType(&RttiTypes::DomainParent) .elementHandler(DomainParentHandler::create) .arguments({Argument::String("name")}); @@ -860,9 +1023,12 @@ static const ParserState Include = static const std::multimap<std::string, const ParserState *> XmlStates{ {"document", &Document}, + {"*", &DocumentChild}, {"domain", &Domain}, {"struct", &DomainStruct}, {"annotation", &DomainAnnotation}, + {"attributes", &DomainAttributes}, + {"attribute", &DomainAttribute}, {"field", &DomainField}, {"fieldRef", &DomainFieldRef}, {"primitive", &DomainStructPrimitive}, |