/* Ousía Copyright (C) 2014, 2015 Benjamin Paaßen, Andreas Stöckel This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "XmlParser.hpp" namespace ousia { /* HeadNode Helper class */ namespace { class HeadNode : public Node { public: using Node::Node; }; } namespace RttiTypes { static Rtti HeadNode = RttiBuilder("HeadNode"); } /* Element Handler Classes */ class DocumentHandler : public Handler { public: using Handler::Handler; void start(Variant::mapType &args) override { Rooted document = project()->createDocument(args["name"].asString()); document->setLocation(location()); scope().push(document); scope().setFlag(ParserFlag::POST_HEAD, false); } void end() override { scope().pop(); } static Handler *create(const HandlerData &handlerData) { return new DocumentHandler{handlerData}; } }; class DocumentField : public Node { public: DocumentField(Manager &mgr, std::string name, Handle parent) : Node(mgr, name, parent) { } }; namespace RttiTypes { const Rtti DocumentField = RttiBuilder("DocumentField").parent(&Node); } class DocumentChildHandler : public Handler { public: using Handler::Handler; void preamble(Handle 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. // TODO: Consider fields of transparent classes if (!inField && parent != nullptr && parent->getDescriptor()->hasField(name())) { 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 { // calculate a path if transparent entities are needed in between. auto path = parent->getDescriptor()->pathTo(strct); 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. for (size_t p = 1; p < path.size() - 1; p = p + 2) { parent = static_cast( parent->createChildStructuredEntity( path[p].cast(), Variant::mapType{}, path[p - 1]->getName(), "").get()); } 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 fieldIdx) 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. // TODO: Consider fields of transparent classes Rooted desc = parent->getDescriptor(); Rooted 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()); return; } if (!field->isPrimitive()) { logger().error(std::string("Can't handle data because field \"") + fieldName + "\" of descriptor \"" + desc->getName() + "\" is not primitive!", location()); return; } // try to parse the content. auto res = VariantReader::parseGenericString( data, logger(), location().getSourceId(), location().getStart()); if (!res.first) { return; } // try to convert it to the correct type. if (!field->getPrimitiveType()->build(res.second, logger())) { return; } // add it as primitive content. parent->createChildDocumentPrimitive(res.second, fieldName); } static Handler *create(const HandlerData &handlerData) { return new DocumentChildHandler{handlerData}; } }; class TypesystemHandler : public Handler { public: using Handler::Handler; void start(Variant::mapType &args) override { // Create the typesystem instance Rooted typesystem = project()->createTypesystem(args["name"].asString()); typesystem->setLocation(location()); // Push the typesystem onto the scope, set the POST_HEAD flag to true scope().push(typesystem); scope().setFlag(ParserFlag::POST_HEAD, false); } void end() override { scope().pop(); } static Handler *create(const HandlerData &handlerData) { return new TypesystemHandler{handlerData}; } }; class TypesystemEnumHandler : public Handler { public: using Handler::Handler; void start(Variant::mapType &args) override { scope().setFlag(ParserFlag::POST_HEAD, true); // Fetch the current typesystem and create the enum node Rooted typesystem = scope().selectOrThrow(); Rooted enumType = typesystem->createEnumType(args["name"].asString()); enumType->setLocation(location()); scope().push(enumType); } void end() override { scope().pop(); } static Handler *create(const HandlerData &handlerData) { return new TypesystemEnumHandler{handlerData}; } }; class TypesystemEnumEntryHandler : public Handler { public: using Handler::Handler; std::string entry; void start(Variant::mapType &args) override {} void end() override { Rooted enumType = scope().selectOrThrow(); enumType->addEntry(entry, logger()); } void data(const std::string &data, int field) override { if (field != 0) { // TODO: This should be stored in the HandlerData logger().error("Enum entry only has one field."); return; } entry.append(data); } static Handler *create(const HandlerData &handlerData) { return new TypesystemEnumEntryHandler{handlerData}; } }; class TypesystemStructHandler : public Handler { public: using Handler::Handler; void start(Variant::mapType &args) override { scope().setFlag(ParserFlag::POST_HEAD, true); // Fetch the arguments used for creating this type const std::string &name = args["name"].asString(); const std::string &parent = args["parent"].asString(); // Fetch the current typesystem and create the struct node Rooted typesystem = scope().selectOrThrow(); Rooted structType = typesystem->createStructType(name); structType->setLocation(location()); // Try to resolve the parent type and set it as parent structure if (!parent.empty()) { scope().resolve( parent, structType, logger(), [](Handle parent, Handle structType, Logger &logger) { if (parent != nullptr) { structType.cast()->setParentStructure( parent.cast(), logger); } }); } scope().push(structType); } void end() override { scope().pop(); } static Handler *create(const HandlerData &handlerData) { return new TypesystemStructHandler{handlerData}; } }; class TypesystemStructFieldHandler : public Handler { public: using Handler::Handler; void start(Variant::mapType &args) override { // Read the argument values const std::string &name = args["name"].asString(); const std::string &type = args["type"].asString(); const Variant &defaultValue = args["default"]; const bool optional = !(defaultValue.isObject() && defaultValue.asObject() == nullptr); Rooted structType = scope().selectOrThrow(); Rooted attribute = structType->createAttribute(name, defaultValue, optional, logger()); attribute->setLocation(location()); // Try to resolve the type and default value if (optional) { scope().resolveTypeWithValue( type, attribute, attribute->getDefaultValue(), logger(), [](Handle type, Handle attribute, Logger &logger) { if (type != nullptr) { attribute.cast()->setType(type.cast(), logger); } }); } else { scope().resolveType( type, attribute, logger(), [](Handle type, Handle attribute, Logger &logger) { if (type != nullptr) { attribute.cast()->setType(type.cast(), logger); } }); } } void end() override {} static Handler *create(const HandlerData &handlerData) { return new TypesystemStructFieldHandler{handlerData}; } }; class TypesystemConstantHandler : public Handler { public: using Handler::Handler; void start(Variant::mapType &args) override { scope().setFlag(ParserFlag::POST_HEAD, true); // Read the argument values const std::string &name = args["name"].asString(); const std::string &type = args["type"].asString(); const Variant &value = args["value"]; Rooted typesystem = scope().selectOrThrow(); Rooted constant = typesystem->createConstant(name, value); constant->setLocation(location()); // Try to resolve the type scope().resolveTypeWithValue( type, constant, constant->getValue(), logger(), [](Handle type, Handle constant, Logger &logger) { if (type != nullptr) { constant.cast()->setType(type.cast(), logger); } }); } void end() override {} static Handler *create(const HandlerData &handlerData) { return new TypesystemConstantHandler{handlerData}; } }; /* * Domain Handlers */ class DomainHandler : public Handler { public: using Handler::Handler; void start(Variant::mapType &args) override { Rooted domain = project()->createDomain(args["name"].asString()); domain->setLocation(location()); scope().push(domain); } void end() override { scope().pop(); } static Handler *create(const HandlerData &handlerData) { return new DomainHandler{handlerData}; } }; class DomainStructHandler : public Handler { public: using Handler::Handler; void start(Variant::mapType &args) override { scope().setFlag(ParserFlag::POST_HEAD, true); Rooted domain = scope().selectOrThrow(); Rooted structuredClass = domain->createStructuredClass( args["name"].asString(), args["cardinality"].asCardinality(), nullptr, args["transparent"].asBool(), args["isRoot"].asBool()); structuredClass->setLocation(location()); const std::string &isa = args["isa"].asString(); if (!isa.empty()) { scope().resolve( isa, structuredClass, logger(), [](Handle superclass, Handle structuredClass, Logger &logger) { if (superclass != nullptr) { structuredClass.cast()->setSuperclass( superclass.cast(), logger); } }); } scope().push(structuredClass); } void end() override { scope().pop(); } static Handler *create(const HandlerData &handlerData) { return new DomainStructHandler{handlerData}; } }; class DomainAnnotationHandler : public Handler { public: using Handler::Handler; void start(Variant::mapType &args) override { scope().setFlag(ParserFlag::POST_HEAD, true); Rooted domain = scope().selectOrThrow(); Rooted annotationClass = domain->createAnnotationClass(args["name"].asString()); annotationClass->setLocation(location()); scope().push(annotationClass); } void end() override { scope().pop(); } static Handler *create(const HandlerData &handlerData) { return new DomainAnnotationHandler{handlerData}; } }; 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; void start(Variant::mapType &args) override { FieldDescriptor::FieldType type; if (args["isSubtree"].asBool()) { type = FieldDescriptor::FieldType::SUBTREE; } else { type = FieldDescriptor::FieldType::TREE; } Rooted parent = scope().selectOrThrow(); Rooted field = parent->createFieldDescriptor( type, args["name"].asString(), args["optional"].asBool()); field->setLocation(location()); scope().push(field); } void end() override { scope().pop(); } static Handler *create(const HandlerData &handlerData) { return new DomainFieldHandler{handlerData}; } }; class DomainFieldRefHandler : public Handler { public: using Handler::Handler; void start(Variant::mapType &args) override { Rooted parent = scope().selectOrThrow(); const std::string &name = args["name"].asString(); scope().resolve( name, parent, logger(), [](Handle field, Handle parent, Logger &logger) { if (field != nullptr) { parent.cast()->addFieldDescriptor( field.cast()); } }); } void end() override {} static Handler *create(const HandlerData &handlerData) { return new DomainFieldRefHandler{handlerData}; } }; class DomainPrimitiveHandler : public Handler { public: using Handler::Handler; void start(Variant::mapType &args) override { Rooted parent = scope().selectOrThrow(); Rooted field = parent->createPrimitiveFieldDescriptor( nullptr, args["name"].asString(), args["optional"].asBool()); field->setLocation(location()); const std::string &type = args["type"].asString(); scope().resolve( type, field, logger(), [](Handle type, Handle field, Logger &logger) { if (type != nullptr) { field.cast()->setPrimitiveType( type.cast()); } }); scope().push(field); } void end() override { scope().pop(); } static Handler *create(const HandlerData &handlerData) { return new DomainPrimitiveHandler{handlerData}; } }; class DomainChildHandler : public Handler { public: using Handler::Handler; void start(Variant::mapType &args) override { Rooted field = scope().selectOrThrow(); const std::string &ref = args["ref"].asString(); scope().resolve( ref, field, logger(), [](Handle child, Handle field, Logger &logger) { if (child != nullptr) { field.cast()->addChild( child.cast()); } }); } void end() override {} static Handler *create(const HandlerData &handlerData) { return new DomainChildHandler{handlerData}; } }; class DomainParent : public Node { public: DomainParent(Manager &mgr, std::string name, Handle parent) : Node(mgr, name, parent) { } }; namespace RttiTypes { const Rtti DomainParent = RttiBuilder("DomainParent").parent(&Node); } class DomainParentHandler : public Handler { public: using Handler::Handler; void start(Variant::mapType &args) override { Rooted strct = scope().selectOrThrow(); Rooted parent{new DomainParent( strct->getManager(), args["name"].asString(), strct)}; parent->setLocation(location()); scope().push(parent); } void end() override { scope().pop(); } static Handler *create(const HandlerData &handlerData) { return new DomainParentHandler{handlerData}; } }; class DomainParentFieldHandler : public Handler { public: using Handler::Handler; void start(Variant::mapType &args) override { Rooted parentNameNode = scope().selectOrThrow(); FieldDescriptor::FieldType type; if (args["isSubtree"].asBool()) { type = FieldDescriptor::FieldType::SUBTREE; } else { type = FieldDescriptor::FieldType::TREE; } const std::string &name = args["name"].asString(); const bool optional = args["optional"].asBool(); Rooted strct = parentNameNode->getParent().cast(); // resolve the parent, create the declared field and add the declared // StructuredClass as child to it. scope().resolve( parentNameNode->getName(), strct, logger(), [type, name, optional](Handle parent, Handle strct, Logger &logger) { if (parent != nullptr) { Rooted field = parent.cast()->createFieldDescriptor( type, name, optional); field->addChild(strct.cast()); } }); } void end() override {} static Handler *create(const HandlerData &handlerData) { return new DomainParentFieldHandler{handlerData}; } }; class DomainParentFieldRefHandler : public Handler { public: using Handler::Handler; void start(Variant::mapType &args) override { Rooted parentNameNode = scope().selectOrThrow(); const std::string &name = args["name"].asString(); Rooted strct = parentNameNode->getParent().cast(); auto loc = location(); // resolve the parent, get the referenced field and add the declared // StructuredClass as child to it. scope().resolve(parentNameNode->getName(), strct, logger(), [name, loc](Handle parent, Handle strct, Logger &logger) { if (parent != nullptr) { auto res = parent.cast()->resolve( &RttiTypes::FieldDescriptor, name); if (res.size() != 1) { logger.error( std::string("Could not find referenced field ") + name, loc); return; } Rooted field = res[0].node.cast(); field->addChild(strct.cast()); } }); } void end() override {} static Handler *create(const HandlerData &handlerData) { return new DomainParentFieldRefHandler{handlerData}; } }; /* * Import and Include Handler */ class ImportIncludeHandler : public Handler { public: using Handler::Handler; bool srcInArgs = false; std::string rel; std::string type; std::string src; void start(Variant::mapType &args) override { rel = args["rel"].asString(); type = args["type"].asString(); src = args["src"].asString(); srcInArgs = !src.empty(); } void data(const std::string &data, int field) override { if (srcInArgs) { logger().error("\"src\" attribute has already been set"); return; } if (field != 0) { logger().error("Command has only one field."); return; } src.append(data); } }; class ImportHandler : public ImportIncludeHandler { public: using ImportIncludeHandler::ImportIncludeHandler; void start(Variant::mapType &args) override { ImportIncludeHandler::start(args); // Make sure imports are still possible if (scope().getFlag(ParserFlag::POST_HEAD)) { logger().error("Imports must be listed before other commands.", location()); return; } } void end() override { // Fetch the last node and check whether an import is valid at this // position Rooted leaf = scope().getLeaf(); if (leaf == nullptr || !leaf->isa(&RttiTypes::RootNode)) { logger().error( "Import not supported here, must be inside a document, domain " "or typesystem command.", location()); return; } Rooted leafRootNode = leaf.cast(); // Perform the actual import, register the imported node within the leaf // node Rooted imported = context().import(src, type, rel, leafRootNode->getReferenceTypes()); if (imported != nullptr) { leafRootNode->reference(imported); } } static Handler *create(const HandlerData &handlerData) { return new ImportHandler{handlerData}; } }; class IncludeHandler : public ImportIncludeHandler { public: using ImportIncludeHandler::ImportIncludeHandler; void start(Variant::mapType &args) override { ImportIncludeHandler::start(args); } void end() override { context().include(src, type, rel, {&RttiTypes::Node}); } static Handler *create(const HandlerData &handlerData) { return new IncludeHandler{handlerData}; } }; namespace ParserStates { /* Document states */ static const ParserState Document = ParserStateBuilder() .parent(&None) .createdNodeType(&RttiTypes::Document) .elementHandler(DocumentHandler::create) .arguments({Argument::String("name", "")}); static const ParserState DocumentChild = ParserStateBuilder() .parents({&Document, &DocumentChild}) .createdNodeTypes({&RttiTypes::StructureNode, &RttiTypes::AnnotationEntity, &RttiTypes::DocumentField}) .elementHandler(DocumentChildHandler::create); /* Domain states */ static const ParserState Domain = ParserStateBuilder() .parents({&None, &Document}) .createdNodeType(&RttiTypes::Domain) .elementHandler(DomainHandler::create) .arguments({Argument::String("name")}); static const ParserState DomainStruct = ParserStateBuilder() .parent(&Domain) .createdNodeType(&RttiTypes::StructuredClass) .elementHandler(DomainStructHandler::create) .arguments({Argument::String("name"), Argument::Cardinality("cardinality", Cardinality::any()), Argument::Bool("isRoot", false), Argument::Bool("transparent", false), Argument::String("isa", "")}); static const ParserState DomainAnnotation = ParserStateBuilder() .parent(&Domain) .createdNodeType(&RttiTypes::AnnotationClass) .elementHandler(DomainAnnotationHandler::create) .arguments({Argument::String("name")}); 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() .parents({&DomainStruct, &DomainAnnotation}) .createdNodeType(&RttiTypes::FieldDescriptor) .elementHandler(DomainFieldHandler::create) .arguments({Argument::String("name", DEFAULT_FIELD_NAME), Argument::Bool("isSubtree", false), Argument::Bool("optional", false)}); static const ParserState DomainFieldRef = ParserStateBuilder() .parents({&DomainStruct, &DomainAnnotation}) .createdNodeType(&RttiTypes::FieldDescriptor) .elementHandler(DomainFieldRefHandler::create) .arguments({Argument::String("name", DEFAULT_FIELD_NAME)}); static const ParserState DomainStructPrimitive = ParserStateBuilder() .parents({&DomainStruct, &DomainAnnotation}) .createdNodeType(&RttiTypes::FieldDescriptor) .elementHandler(DomainPrimitiveHandler::create) .arguments({Argument::String("name", DEFAULT_FIELD_NAME), Argument::Bool("optional", false), Argument::String("type")}); static const ParserState DomainStructChild = ParserStateBuilder() .parent(&DomainField) .elementHandler(DomainChildHandler::create) .arguments({Argument::String("ref")}); static const ParserState DomainStructParent = ParserStateBuilder() .parent(&DomainStruct) .createdNodeType(&RttiTypes::DomainParent) .elementHandler(DomainParentHandler::create) .arguments({Argument::String("name")}); static const ParserState DomainStructParentField = ParserStateBuilder() .parent(&DomainStructParent) .createdNodeType(&RttiTypes::FieldDescriptor) .elementHandler(DomainParentFieldHandler::create) .arguments({Argument::String("name", DEFAULT_FIELD_NAME), Argument::Bool("isSubtree", false), Argument::Bool("optional", false)}); static const ParserState DomainStructParentFieldRef = ParserStateBuilder() .parent(&DomainStructParent) .createdNodeType(&RttiTypes::FieldDescriptor) .elementHandler(DomainParentFieldRefHandler::create) .arguments({Argument::String("name", DEFAULT_FIELD_NAME)}); /* Typesystem states */ static const ParserState Typesystem = ParserStateBuilder() .parents({&None, &Domain}) .createdNodeType(&RttiTypes::Typesystem) .elementHandler(TypesystemHandler::create) .arguments({Argument::String("name", "")}); static const ParserState TypesystemEnum = ParserStateBuilder() .parent(&Typesystem) .createdNodeType(&RttiTypes::EnumType) .elementHandler(TypesystemEnumHandler::create) .arguments({Argument::String("name")}); static const ParserState TypesystemEnumEntry = ParserStateBuilder() .parent(&TypesystemEnum) .elementHandler(TypesystemEnumEntryHandler::create) .arguments({}); static const ParserState TypesystemStruct = ParserStateBuilder() .parent(&Typesystem) .createdNodeType(&RttiTypes::StructType) .elementHandler(TypesystemStructHandler::create) .arguments({Argument::String("name"), Argument::String("parent", "")}); static const ParserState TypesystemStructField = ParserStateBuilder() .parent(&TypesystemStruct) .elementHandler(TypesystemStructFieldHandler::create) .arguments({Argument::String("name"), Argument::String("type"), Argument::Any("default", Variant::fromObject(nullptr))}); static const ParserState TypesystemConstant = ParserStateBuilder() .parent(&Typesystem) .createdNodeType(&RttiTypes::Constant) .elementHandler(TypesystemConstantHandler::create) .arguments({Argument::String("name"), Argument::String("type"), Argument::Any("value")}); /* Special states for import and include */ static const ParserState Import = ParserStateBuilder() .parents({&Document, &Typesystem, &Domain}) .elementHandler(ImportHandler::create) .arguments({Argument::String("rel", ""), Argument::String("type", ""), Argument::String("src", "")}); static const ParserState Include = ParserStateBuilder() .parent(&All) .elementHandler(IncludeHandler::create) .arguments({Argument::String("rel", ""), Argument::String("type", ""), Argument::String("src", "")}); static const std::multimap XmlStates{ {"document", &Document}, {"*", &DocumentChild}, {"domain", &Domain}, {"struct", &DomainStruct}, {"annotation", &DomainAnnotation}, {"attributes", &DomainAttributes}, {"attribute", &DomainAttribute}, {"field", &DomainField}, {"fieldRef", &DomainFieldRef}, {"primitive", &DomainStructPrimitive}, {"child", &DomainStructChild}, {"parent", &DomainStructParent}, {"field", &DomainStructParentField}, {"fieldRef", &DomainStructParentFieldRef}, {"typesystem", &Typesystem}, {"enum", &TypesystemEnum}, {"entry", &TypesystemEnumEntry}, {"struct", &TypesystemStruct}, {"field", &TypesystemStructField}, {"constant", &TypesystemConstant}, {"import", &Import}, {"include", &Include}}; } }