diff options
author | John McCall <rjmccall@apple.com> | 2019-12-16 02:10:15 -0500 |
---|---|---|
committer | John McCall <rjmccall@apple.com> | 2019-12-16 13:33:59 -0500 |
commit | efd0dfbd700d724f148468e707b8ba5f28e847e6 (patch) | |
tree | f6970312c93086b462cfc8bb06e30139601d7409 /clang/utils | |
parent | 41d935f2c619821f4cde05ad779265ebaac5fcd7 (diff) | |
download | bcm5719-llvm-efd0dfbd700d724f148468e707b8ba5f28e847e6.tar.gz bcm5719-llvm-efd0dfbd700d724f148468e707b8ba5f28e847e6.zip |
Add the ability to use property-based serialization for "cased" types.
This patch doesn't actually use this serialization for anything,
but follow-ups will move the current handling of various standard
types over to this.
Diffstat (limited to 'clang/utils')
-rw-r--r-- | clang/utils/TableGen/ASTTableGen.cpp | 10 | ||||
-rw-r--r-- | clang/utils/TableGen/ASTTableGen.h | 137 | ||||
-rw-r--r-- | clang/utils/TableGen/ClangASTNodesEmitter.cpp | 2 | ||||
-rw-r--r-- | clang/utils/TableGen/ClangASTPropertiesEmitter.cpp | 265 |
4 files changed, 335 insertions, 79 deletions
diff --git a/clang/utils/TableGen/ASTTableGen.cpp b/clang/utils/TableGen/ASTTableGen.cpp index c49bcd9202f..3f6da40964e 100644 --- a/clang/utils/TableGen/ASTTableGen.cpp +++ b/clang/utils/TableGen/ASTTableGen.cpp @@ -20,6 +20,16 @@ using namespace llvm; using namespace clang; using namespace clang::tblgen; +llvm::StringRef clang::tblgen::HasProperties::getName() const { + if (auto node = getAs<ASTNode>()) { + return node.getName(); + } else if (auto typeCase = getAs<TypeCase>()) { + return typeCase.getCaseName(); + } else { + PrintFatalError(getLoc(), "unexpected node declaring properties"); + } +} + static StringRef removeExpectedNodeNameSuffix(Record *node, StringRef suffix) { StringRef nodeName = node->getName(); if (!nodeName.endswith(suffix)) { diff --git a/clang/utils/TableGen/ASTTableGen.h b/clang/utils/TableGen/ASTTableGen.h index 87934f502eb..7b7e5f128c8 100644 --- a/clang/utils/TableGen/ASTTableGen.h +++ b/clang/utils/TableGen/ASTTableGen.h @@ -14,7 +14,11 @@ // These are spellings in the tblgen files. -// Field names that are fortunately common across the hierarchies. +#define HasPropertiesClassName "HasProperties" + +// ASTNodes and their common fields. `Base` is actually defined +// in subclasses, but it's still common across the hierarchies. +#define ASTNodeClassName "ASTNode" #define BaseFieldName "Base" #define AbstractFieldName "Abstract" @@ -35,6 +39,12 @@ #define NeverCanonicalUnlessDependentClassName "NeverCanonicalUnlessDependent" #define LeafTypeClassName "LeafType" +// Cases of various non-ASTNode structured types like DeclarationName. +#define TypeKindClassName "PropertyTypeKind" +#define KindTypeFieldName "KindType" +#define KindPropertyNameFieldName "KindPropertyName" +#define TypeCaseClassName "PropertyTypeCase" + // Properties of AST nodes. #define PropertyClassName "Property" #define ClassFieldName "Class" @@ -94,13 +104,54 @@ public: bool isSubClassOf(llvm::StringRef className) const { return get()->isSubClassOf(className); } + + template <class NodeClass> + NodeClass getAs() const { + return (isSubClassOf(NodeClass::getTableGenNodeClassName()) + ? NodeClass(get()) : NodeClass()); + } + + friend bool operator<(WrappedRecord lhs, WrappedRecord rhs) { + assert(lhs && rhs && "sorting null nodes"); + return lhs.get()->getName() < rhs.get()->getName(); + } + friend bool operator>(WrappedRecord lhs, WrappedRecord rhs) { + return rhs < lhs; + } + friend bool operator<=(WrappedRecord lhs, WrappedRecord rhs) { + return !(rhs < lhs); + } + friend bool operator>=(WrappedRecord lhs, WrappedRecord rhs) { + return !(lhs < rhs); + } + friend bool operator==(WrappedRecord lhs, WrappedRecord rhs) { + // This should handle null nodes. + return lhs.getRecord() == rhs.getRecord(); + } + friend bool operator!=(WrappedRecord lhs, WrappedRecord rhs) { + return !(lhs == rhs); + } +}; + +/// Anything in the AST that has properties. +class HasProperties : public WrappedRecord { +public: + static constexpr llvm::StringRef ClassName = HasPropertiesClassName; + + HasProperties(llvm::Record *record = nullptr) : WrappedRecord(record) {} + + llvm::StringRef getName() const; + + static llvm::StringRef getTableGenNodeClassName() { + return HasPropertiesClassName; + } }; /// An (optional) reference to a TableGen node representing a class /// in one of Clang's AST hierarchies. -class ASTNode : public WrappedRecord { +class ASTNode : public HasProperties { public: - ASTNode(llvm::Record *record = nullptr) : WrappedRecord(record) {} + ASTNode(llvm::Record *record = nullptr) : HasProperties(record) {} llvm::StringRef getName() const { return get()->getName(); @@ -116,19 +167,9 @@ public: return get()->getValueAsBit(AbstractFieldName); } - friend bool operator<(ASTNode lhs, ASTNode rhs) { - assert(lhs && rhs && "sorting null nodes"); - return lhs.getName() < rhs.getName(); - } - friend bool operator>(ASTNode lhs, ASTNode rhs) { return rhs < lhs; } - friend bool operator<=(ASTNode lhs, ASTNode rhs) { return !(rhs < lhs); } - friend bool operator>=(ASTNode lhs, ASTNode rhs) { return !(lhs < rhs); } - - friend bool operator==(ASTNode lhs, ASTNode rhs) { - // This should handle null nodes. - return lhs.getRecord() == rhs.getRecord(); + static llvm::StringRef getTableGenNodeClassName() { + return ASTNodeClassName; } - friend bool operator!=(ASTNode lhs, ASTNode rhs) { return !(lhs == rhs); } }; class DeclNode : public ASTNode { @@ -275,6 +316,60 @@ public: std::vector<llvm::Record*> getBufferElementTypes() const { return get()->getValueAsListOfDefs(BufferElementTypesFieldName); } + + static llvm::StringRef getTableGenNodeClassName() { + return PropertyTypeClassName; + } +}; + +/// A rule for returning the kind of a type. +class TypeKindRule : public WrappedRecord { +public: + TypeKindRule(llvm::Record *record = nullptr) : WrappedRecord(record) {} + + /// Return the type to which this applies. + PropertyType getParentType() const { + return get()->getValueAsDef(TypeFieldName); + } + + /// Return the type of the kind. + PropertyType getKindType() const { + return get()->getValueAsDef(KindTypeFieldName); + } + + /// Return the name to use for the kind property. + llvm::StringRef getKindPropertyName() const { + return get()->getValueAsString(KindPropertyNameFieldName); + } + + /// Return the code for reading the kind value. + llvm::StringRef getReadCode() const { + return get()->getValueAsString(ReadFieldName); + } + + static llvm::StringRef getTableGenNodeClassName() { + return TypeKindClassName; + } +}; + +/// An implementation case of a property type. +class TypeCase : public HasProperties { +public: + TypeCase(llvm::Record *record = nullptr) : HasProperties(record) {} + + /// Return the name of this case. + llvm::StringRef getCaseName() const { + return get()->getValueAsString(NameFieldName); + } + + /// Return the type of which this is a case. + PropertyType getParentType() const { + return get()->getValueAsDef(TypeFieldName); + } + + static llvm::StringRef getTableGenNodeClassName() { + return TypeCaseClassName; + } }; /// A property of an AST node. @@ -301,6 +396,10 @@ public: llvm::StringRef getReadCode() const { return get()->getValueAsString(ReadFieldName); } + + static llvm::StringRef getTableGenNodeClassName() { + return PropertyClassName; + } }; /// A rule for how to create an AST node from its properties. @@ -317,6 +416,10 @@ public: llvm::StringRef getCreationCode() const { return get()->getValueAsString(CreateFieldName); } + + static llvm::StringRef getTableGenNodeClassName() { + return CreationRuleClassName; + } }; /// A rule which overrides the standard rules for serializing an AST node. @@ -336,6 +439,10 @@ public: std::vector<llvm::StringRef> getIgnoredProperties() const { return get()->getValueAsListOfStrings(IgnoredPropertiesFieldName); } + + static llvm::StringRef getTableGenNodeClassName() { + return OverrideRuleClassName; + } }; /// A visitor for an AST node hierarchy. Note that `base` can be null for diff --git a/clang/utils/TableGen/ClangASTNodesEmitter.cpp b/clang/utils/TableGen/ClangASTNodesEmitter.cpp index c1bb00bf7b9..1cc46cb0657 100644 --- a/clang/utils/TableGen/ClangASTNodesEmitter.cpp +++ b/clang/utils/TableGen/ClangASTNodesEmitter.cpp @@ -142,7 +142,7 @@ std::pair<ASTNode, ASTNode> ClangASTNodesEmitter::EmitNode(raw_ostream &OS, } void ClangASTNodesEmitter::deriveChildTree() { - assert(Root == nullptr && "already computed tree"); + assert(!Root && "already computed tree"); // Emit statements const std::vector<Record*> Stmts diff --git a/clang/utils/TableGen/ClangASTPropertiesEmitter.cpp b/clang/utils/TableGen/ClangASTPropertiesEmitter.cpp index e14b9eb6e6f..81d880c61a6 100644 --- a/clang/utils/TableGen/ClangASTPropertiesEmitter.cpp +++ b/clang/utils/TableGen/ClangASTPropertiesEmitter.cpp @@ -80,11 +80,17 @@ struct NodeInfo { OverrideRule Override = nullptr; }; +struct CasedTypeInfo { + TypeKindRule KindRule; + std::vector<TypeCase> Cases; +}; + class ASTPropsEmitter { raw_ostream &Out; RecordKeeper &Records; - std::map<ASTNode, NodeInfo> NodeInfos; + std::map<HasProperties, NodeInfo> NodeInfos; std::vector<PropertyType> AllPropertyTypes; + std::map<PropertyType, CasedTypeInfo> CasedTypeInfos; public: ASTPropsEmitter(RecordKeeper &records, raw_ostream &out) @@ -125,6 +131,7 @@ public: info.Override = overrideRule; } + // Find all the concrete property types. for (PropertyType type : records.getAllDerivedDefinitions(PropertyTypeClassName)) { // Ignore generic specializations; they're generally not useful when @@ -134,10 +141,29 @@ public: AllPropertyTypes.push_back(type); } + // Find all the type kind rules. + for (TypeKindRule kindRule : + records.getAllDerivedDefinitions(TypeKindClassName)) { + PropertyType type = kindRule.getParentType(); + auto &info = CasedTypeInfos[type]; + if (info.KindRule) { + PrintFatalError(kindRule.getLoc(), + "multiple kind rules for \"" + + type.getCXXTypeName() + "\""); + } + info.KindRule = kindRule; + } + + // Find all the type cases. + for (TypeCase typeCase : + records.getAllDerivedDefinitions(TypeCaseClassName)) { + CasedTypeInfos[typeCase.getParentType()].Cases.push_back(typeCase); + } + Validator(*this).validate(); } - void visitAllProperties(ASTNode derived, const NodeInfo &derivedInfo, + void visitAllProperties(HasProperties derived, const NodeInfo &derivedInfo, function_ref<void (Property)> visit) { std::set<StringRef> ignoredProperties; @@ -147,60 +173,88 @@ public: ignoredProperties.insert(list.begin(), list.end()); } - for (ASTNode node = derived; node; node = node.getBase()) { - auto it = NodeInfos.find(node); - - // Ignore intermediate nodes that don't add interesting properties. - if (it == NodeInfos.end()) continue; - auto &info = it->second; - + visitAllNodesWithInfo(derived, derivedInfo, + [&](HasProperties node, const NodeInfo &info) { for (Property prop : info.Properties) { if (ignoredProperties.count(prop.getName())) continue; visit(prop); } + }); + } + + void visitAllNodesWithInfo(HasProperties derivedNode, + const NodeInfo &derivedNodeInfo, + llvm::function_ref<void (HasProperties node, + const NodeInfo &info)> + visit) { + visit(derivedNode, derivedNodeInfo); + + // Also walk the bases if appropriate. + if (ASTNode base = derivedNode.getAs<ASTNode>()) { + for (base = base.getBase(); base; base = base.getBase()) { + auto it = NodeInfos.find(base); + + // Ignore intermediate nodes that don't add interesting properties. + if (it == NodeInfos.end()) continue; + auto &baseInfo = it->second; + + visit(base, baseInfo); + } } } template <class NodeClass> - void emitReaderClass() { + void emitNodeReaderClass() { auto info = ReaderWriterInfo::forReader<NodeClass>(); - emitReaderWriterClass<NodeClass>(info); + emitNodeReaderWriterClass<NodeClass>(info); } template <class NodeClass> - void emitWriterClass() { + void emitNodeWriterClass() { auto info = ReaderWriterInfo::forWriter<NodeClass>(); - emitReaderWriterClass<NodeClass>(info); + emitNodeReaderWriterClass<NodeClass>(info); } template <class NodeClass> - void emitReaderWriterClass(const ReaderWriterInfo &info); + void emitNodeReaderWriterClass(const ReaderWriterInfo &info); template <class NodeClass> void emitNodeReaderWriterMethod(NodeClass node, const ReaderWriterInfo &info); - void emitReadOfProperty(Property property); - void emitWriteOfProperty(Property property); + void emitPropertiedReaderWriterBody(HasProperties node, + const ReaderWriterInfo &info); + + void emitReadOfProperty(StringRef readerName, Property property); + void emitReadOfProperty(StringRef readerName, StringRef name, + PropertyType type); + + void emitWriteOfProperty(StringRef writerName, Property property); + void emitWriteOfProperty(StringRef writerName, StringRef name, + PropertyType type, StringRef readCode); void emitBasicReaderWriterFile(const ReaderWriterInfo &info); void emitDispatcherTemplate(const ReaderWriterInfo &info); void emitPackUnpackOptionalTemplate(const ReaderWriterInfo &info); void emitBasicReaderWriterTemplate(const ReaderWriterInfo &info); + void emitCasedReaderWriterMethodBody(PropertyType type, + const CasedTypeInfo &typeCases, + const ReaderWriterInfo &info); + private: class Validator { - const ASTPropsEmitter &Emitter; - std::set<ASTNode> ValidatedNodes; + ASTPropsEmitter &Emitter; + std::set<HasProperties> ValidatedNodes; public: - Validator(const ASTPropsEmitter &emitter) : Emitter(emitter) {} + Validator(ASTPropsEmitter &emitter) : Emitter(emitter) {} void validate(); private: - void validateNode(ASTNode node, const NodeInfo &nodeInfo); + void validateNode(HasProperties node, const NodeInfo &nodeInfo); void validateType(PropertyType type, WrappedRecord context); }; }; @@ -217,21 +271,17 @@ void ASTPropsEmitter::Validator::validate() { } } -void ASTPropsEmitter::Validator::validateNode(ASTNode node, - const NodeInfo &nodeInfo) { - if (!ValidatedNodes.insert(node).second) return; +void ASTPropsEmitter::Validator::validateNode(HasProperties derivedNode, + const NodeInfo &derivedNodeInfo) { + if (!ValidatedNodes.insert(derivedNode).second) return; // A map from property name to property. std::map<StringRef, Property> allProperties; - // Walk the hierarchy, ignoring nodes that don't declare anything - // interesting. - for (auto base = node; base; base = base.getBase()) { - auto it = Emitter.NodeInfos.find(base); - if (it == Emitter.NodeInfos.end()) continue; - - auto &baseInfo = it->second; - for (Property property : baseInfo.Properties) { + Emitter.visitAllNodesWithInfo(derivedNode, derivedNodeInfo, + [&](HasProperties node, + const NodeInfo &nodeInfo) { + for (Property property : nodeInfo.Properties) { validateType(property.getType(), property); auto result = allProperties.insert( @@ -244,11 +294,11 @@ void ASTPropsEmitter::Validator::validateNode(ASTNode node, Property existingProperty = result.first->second; PrintError(existingProperty.getLoc(), "multiple properties named \"" + property.getName() - + "\" in hierarchy of " + node.getName()); + + "\" in hierarchy of " + derivedNode.getName()); PrintNote(property.getLoc(), "existing property"); } } - } + }); } void ASTPropsEmitter::Validator::validateType(PropertyType type, @@ -284,7 +334,7 @@ void ASTPropsEmitter::Validator::validateType(PropertyType type, /****************************************************************************/ template <class NodeClass> -void ASTPropsEmitter::emitReaderWriterClass(const ReaderWriterInfo &info) { +void ASTPropsEmitter::emitNodeReaderWriterClass(const ReaderWriterInfo &info) { StringRef suffix = info.ClassSuffix; StringRef var = info.HelperVariable; @@ -350,6 +400,14 @@ void ASTPropsEmitter::emitNodeReaderWriterMethod(NodeClass node, if (info.IsReader) Out << " auto &ctx = " << info.HelperVariable << ".getASTContext();\n"; + emitPropertiedReaderWriterBody(node, info); + + // Finish the method declaration. + Out << " }\n\n"; +} + +void ASTPropsEmitter::emitPropertiedReaderWriterBody(HasProperties node, + const ReaderWriterInfo &info) { // Find the information for this node. auto it = NodeInfos.find(node); if (it == NodeInfos.end()) @@ -380,17 +438,14 @@ void ASTPropsEmitter::emitNodeReaderWriterMethod(NodeClass node, // Emit code to read or write this property. if (info.IsReader) - emitReadOfProperty(prop); + emitReadOfProperty(info.HelperVariable, prop); else - emitWriteOfProperty(prop); + emitWriteOfProperty(info.HelperVariable, prop); }); // Emit the final creation code. if (info.IsReader) Out << " " << creationCode << "\n"; - - // Finish the method declaration. - Out << " }\n\n"; } static void emitBasicReaderWriterMethodSuffix(raw_ostream &out, @@ -422,10 +477,14 @@ static void emitBasicReaderWriterMethodSuffix(raw_ostream &out, } /// Emit code to read the given property in a node-reader method. -void ASTPropsEmitter::emitReadOfProperty(Property property) { - PropertyType type = property.getType(); - auto name = property.getName(); +void ASTPropsEmitter::emitReadOfProperty(StringRef readerName, + Property property) { + emitReadOfProperty(readerName, property.getName(), property.getType()); +} +void ASTPropsEmitter::emitReadOfProperty(StringRef readerName, + StringRef name, + PropertyType type) { // Declare all the necessary buffers. auto bufferTypes = type.getBufferElementTypes(); for (size_t i = 0, e = bufferTypes.size(); i != e; ++i) { @@ -440,7 +499,7 @@ void ASTPropsEmitter::emitReadOfProperty(Property property) { // that in the creation rule. Out << " "; type.emitCXXValueTypeName(true, Out); - Out << " " << name << " = R.find(\"" << name << "\")." + Out << " " << name << " = " << readerName << ".find(\"" << name << "\")." << (type.isGenericSpecialization() ? "template " : "") << "read"; emitBasicReaderWriterMethodSuffix(Out, type, /*for read*/ true); Out << "("; @@ -451,13 +510,21 @@ void ASTPropsEmitter::emitReadOfProperty(Property property) { } /// Emit code to write the given property in a node-writer method. -void ASTPropsEmitter::emitWriteOfProperty(Property property) { +void ASTPropsEmitter::emitWriteOfProperty(StringRef writerName, + Property property) { + emitWriteOfProperty(writerName, property.getName(), property.getType(), + property.getReadCode()); +} + +void ASTPropsEmitter::emitWriteOfProperty(StringRef writerName, + StringRef name, + PropertyType type, + StringRef readCode) { // Focus down to the property: // W.find("prop").write##ValueType(value); - Out << " W.find(\"" << property.getName() << "\").write"; - emitBasicReaderWriterMethodSuffix(Out, property.getType(), - /*for read*/ false); - Out << "(" << property.getReadCode() << ");\n"; + Out << " " << writerName << ".find(\"" << name << "\").write"; + emitBasicReaderWriterMethodSuffix(Out, type, /*for read*/ false); + Out << "(" << readCode << ");\n"; } /// Emit an .inc file that defines the AbstractFooReader class @@ -467,7 +534,7 @@ static void emitASTReader(RecordKeeper &records, raw_ostream &out, StringRef description) { emitSourceFileHeader(description, out); - ASTPropsEmitter(records, out).emitReaderClass<NodeClass>(); + ASTPropsEmitter(records, out).emitNodeReaderClass<NodeClass>(); } void clang::EmitClangTypeReader(RecordKeeper &records, raw_ostream &out) { @@ -481,7 +548,7 @@ static void emitASTWriter(RecordKeeper &records, raw_ostream &out, StringRef description) { emitSourceFileHeader(description, out); - ASTPropsEmitter(records, out).emitWriterClass<NodeClass>(); + ASTPropsEmitter(records, out).emitNodeWriterClass<NodeClass>(); } void clang::EmitClangTypeWriter(RecordKeeper &records, raw_ostream &out) { @@ -596,35 +663,49 @@ ASTPropsEmitter::emitBasicReaderWriterTemplate(const ReaderWriterInfo &info) { auto enterReaderWriterMethod = [&](StringRef cxxTypeName, StringRef abstractTypeName, bool shouldPassByReference, - bool constWhenWriting) { + bool constWhenWriting, + StringRef paramName) { Out << " " << (info.IsReader ? cxxTypeName : "void") << " " << info.MethodPrefix << abstractTypeName << "("; if (!info.IsReader) Out << (shouldPassByReference || constWhenWriting ? "const " : "") << cxxTypeName - << (shouldPassByReference ? " &" : "") << " value"; + << (shouldPassByReference ? " &" : "") << " " << paramName; Out << ") {\n"; }; // Emit {read,write}ValueType methods for all the enum and subclass types // that default to using the integer/base-class implementations. for (PropertyType type : AllPropertyTypes) { - if (type.isEnum()) { + auto enterMethod = [&](StringRef paramName) { enterReaderWriterMethod(type.getCXXTypeName(), type.getAbstractTypeName(), - /*pass by reference*/ false, - /*const when writing*/ false); + type.shouldPassByReference(), + type.isConstWhenWriting(), + paramName); + }; + auto exitMethod = [&] { + Out << " }\n"; + }; + + // Handled cased types. + auto casedIter = CasedTypeInfos.find(type); + if (casedIter != CasedTypeInfos.end()) { + enterMethod("node"); + emitCasedReaderWriterMethodBody(type, casedIter->second, info); + exitMethod(); + + } else if (type.isEnum()) { + enterMethod("value"); if (info.IsReader) Out << " return " << type.getCXXTypeName() << "(asImpl().readUInt32());\n"; else Out << " asImpl().writeUInt32(uint32_t(value));\n"; - Out << " }\n"; + exitMethod(); + } else if (PropertyType superclass = type.getSuperclassType()) { - enterReaderWriterMethod(type.getCXXTypeName(), - type.getAbstractTypeName(), - /*pass by reference*/ false, - /*const when writing*/ type.isConstWhenWriting()); + enterMethod("value"); if (info.IsReader) Out << " return cast_or_null<" << type.getSubclassClassName() << ">(asImpl().read" @@ -633,7 +714,8 @@ ASTPropsEmitter::emitBasicReaderWriterTemplate(const ReaderWriterInfo &info) { else Out << " asImpl().write" << superclass.getAbstractTypeName() << "(value);\n"; - Out << " }\n"; + exitMethod(); + } else { // The other types can't be handled as trivially. } @@ -641,9 +723,66 @@ ASTPropsEmitter::emitBasicReaderWriterTemplate(const ReaderWriterInfo &info) { Out << "};\n\n"; } -void ASTPropsEmitter::emitBasicReaderWriterFile(const ReaderWriterInfo &info) { - auto types = Records.getAllDerivedDefinitions(PropertyTypeClassName); +void ASTPropsEmitter::emitCasedReaderWriterMethodBody(PropertyType type, + const CasedTypeInfo &typeCases, + const ReaderWriterInfo &info) { + if (typeCases.Cases.empty()) { + assert(typeCases.KindRule); + PrintFatalError(typeCases.KindRule.getLoc(), + "no cases found for \"" + type.getCXXTypeName() + "\""); + } + if (!typeCases.KindRule) { + assert(!typeCases.Cases.empty()); + PrintFatalError(typeCases.Cases.front().getLoc(), + "no kind rule for \"" + type.getCXXTypeName() + "\""); + } + + auto var = info.HelperVariable; + std::string subvar = ("sub" + var).str(); + + // Bind `ctx` for readers. + if (info.IsReader) + Out << " auto &ctx = asImpl().getASTContext();\n"; + // Start an object. + Out << " auto &&" << subvar << " = asImpl()." + << info.MethodPrefix << "Object();\n"; + + // Read/write the kind property; + TypeKindRule kindRule = typeCases.KindRule; + StringRef kindProperty = kindRule.getKindPropertyName(); + PropertyType kindType = kindRule.getKindType(); + if (info.IsReader) { + emitReadOfProperty(subvar, kindProperty, kindType); + } else { + // Read the kind into a local variable. + Out << " "; + kindType.emitCXXValueTypeName(/*for read*/ false, Out); + Out << " " << kindProperty << " = " << kindRule.getReadCode() << ";\n"; + emitWriteOfProperty(subvar, kindProperty, kindType, kindProperty); + } + + // Prepare a ReaderWriterInfo with a helper variable that will use + // the sub-reader/writer. + ReaderWriterInfo subInfo = info; + subInfo.HelperVariable = subvar; + + // Switch on the kind. + Out << " switch (" << kindProperty << ") {\n"; + for (TypeCase typeCase : typeCases.Cases) { + Out << " case " << type.getCXXTypeName() << "::" + << typeCase.getCaseName() << ": {\n"; + emitPropertiedReaderWriterBody(typeCase, subInfo); + if (!info.IsReader) + Out << " return;\n"; + Out << " }\n\n"; + } + Out << " }\n" + " llvm_unreachable(\"bad " << kindType.getCXXTypeName() + << "\");\n"; +} + +void ASTPropsEmitter::emitBasicReaderWriterFile(const ReaderWriterInfo &info) { emitDispatcherTemplate(info); emitPackUnpackOptionalTemplate(info); emitBasicReaderWriterTemplate(info); |