From 72848f6155c40e88572723a39852473a8be3b5bd Mon Sep 17 00:00:00 2001 From: Benjamin Paassen Date: Fri, 6 Feb 2015 16:47:12 +0100 Subject: started to implement document parsing. --- src/plugins/xml/XmlParser.cpp | 205 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 182 insertions(+), 23 deletions(-) (limited to 'src/plugins/xml/XmlParser.cpp') diff --git a/src/plugins/xml/XmlParser.cpp b/src/plugins/xml/XmlParser.cpp index 2d62c11..6a2b160 100644 --- a/src/plugins/xml/XmlParser.cpp +++ b/src/plugins/xml/XmlParser.cpp @@ -75,6 +75,129 @@ public: } }; +class DocumentField : public Node { +public: + DocumentField(Manager &mgr, std::string name, Handle parent, + Handle descriptor) + : Node(mgr, name, parent) + { + } +}; + +namespace RttiTypes { +const Rtti DocumentField = + RttiBuilder("DocumentField").parent(&Node); +} + +class DocumentChildHandler : public Handler { +public: + using Handler::Handler; + + void preamble(Hanlde 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( + parentNode.cast().get()); + } else if (parentNode->isa(RttiTypes::AnnotationEntity)) { + parent = static_cast( + parentNode.cast().get()); + } + } + + void start(Variant::mapType &args) override + { + scope().setFlag(ParserFlag::POST_HEAD, true); + Rooted 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 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 strct = scope().resolve( + 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 entity; + if (parentNode->isa(RttiTypes::Document)) { + entity = parentNode.cast()->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 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{}); + } + + static Handler *create(const HandlerData &handlerData) + { + return new DocumentChildHandler{handlerData}; + } +}; + class TypesystemHandler : public Handler { public: using Handler::Handler; @@ -315,8 +438,7 @@ public: Rooted 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 +449,7 @@ public: Logger &logger) { if (superclass != nullptr) { structuredClass.cast()->setSuperclass( - superclass.cast()); + superclass.cast(), logger); } }); } @@ -354,7 +476,7 @@ public: Rooted domain = scope().selectOrThrow(); Rooted annotationClass = - domain->createAnnotationClass(args["name"].asString(), nullptr); + domain->createAnnotationClass(args["name"].asString()); annotationClass->setLocation(location()); scope().push(annotationClass); @@ -368,6 +490,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 parent = scope().selectOrThrow(); + + Rooted 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 +631,17 @@ public: } }; -class DummyParentNode : public Node { +class DomainParent : public Node { public: - DummyParentNode(Manager &mgr, std::string name, Handle parent) + DomainParent(Manager &mgr, std::string name, Handle parent) : Node(mgr, name, parent) { } }; namespace RttiTypes { -const Rtti DummyParentNode = - RttiBuilder("DummyParentNode").parent(&Node); +const Rtti DomainParent = + RttiBuilder("DomainParent").parent(&Node); } class DomainParentHandler : public Handler { @@ -508,11 +653,10 @@ public: Rooted strct = scope().selectOrThrow(); - // TODO: Is there a better way for this? - Rooted dummy{new DummyParentNode( + Rooted 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 +673,8 @@ public: void start(Variant::mapType &args) override { - Rooted dummy = - scope().selectOrThrow(); + Rooted parentNameNode = + scope().selectOrThrow(); FieldDescriptor::FieldType type; if (args["isSubtree"].asBool()) { type = FieldDescriptor::FieldType::SUBTREE; @@ -541,12 +685,12 @@ public: const std::string &name = args["name"].asString(); const bool optional = args["optional"].asBool(); Rooted strct = - dummy->getParent().cast(); + parentNameNode->getParent().cast(); // resolve the parent, create the declared field and add the declared // StructuredClass as child to it. scope().resolve( - dummy->getName(), strct, logger(), + parentNameNode->getName(), strct, logger(), [&type, &name, &optional](Handle parent, Handle strct, Logger &logger) { if (parent != nullptr) { @@ -572,17 +716,17 @@ public: void start(Variant::mapType &args) override { - Rooted dummy = - scope().selectOrThrow(); + Rooted parentNameNode = + scope().selectOrThrow(); const std::string &name = args["name"].asString(); Rooted strct = - dummy->getParent().cast(); + parentNameNode->getParent().cast(); auto loc = location(); // resolve the parent, get the referenced field and add the declared // StructuredClass as child to it. - scope().resolve(dummy->getName(), strct, logger(), + scope().resolve(parentNameNode->getName(), strct, logger(), [&name, &loc](Handle parent, Handle strct, Logger &logger) { @@ -717,6 +861,7 @@ static const ParserState Document = .parent(&None) .createdNodeType(&RttiTypes::Document) .elementHandler(DocumentHandler::create) + .childHandler(DocumentChildHandler::create) .arguments({Argument::String("name", "")}); /* Domain states */ @@ -736,7 +881,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 +888,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 +937,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")}); @@ -863,6 +1020,8 @@ static const std::multimap XmlStates{ {"domain", &Domain}, {"struct", &DomainStruct}, {"annotation", &DomainAnnotation}, + {"attributes", &DomainAttributes}, + {"attribute", &DomainAttribute}, {"field", &DomainField}, {"fieldRef", &DomainFieldRef}, {"primitive", &DomainStructPrimitive}, -- cgit v1.2.3