From efd0dfbd700d724f148468e707b8ba5f28e847e6 Mon Sep 17 00:00:00 2001 From: John McCall Date: Mon, 16 Dec 2019 02:10:15 -0500 Subject: [PATCH] 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. --- clang/include/clang/AST/AbstractBasicReader.h | 32 +++ clang/include/clang/AST/AbstractBasicWriter.h | 31 +++ clang/include/clang/AST/PropertiesBase.td | 42 +++- clang/include/clang/Basic/ASTNode.td | 8 + clang/include/clang/Basic/CommentNodes.td | 4 +- clang/include/clang/Basic/DeclNodes.td | 3 +- clang/include/clang/Basic/StmtNodes.td | 3 +- clang/include/clang/Basic/TypeNodes.td | 2 +- clang/utils/TableGen/ASTTableGen.cpp | 10 + clang/utils/TableGen/ASTTableGen.h | 137 +++++++++-- clang/utils/TableGen/ClangASTNodesEmitter.cpp | 2 +- clang/utils/TableGen/ClangASTPropertiesEmitter.cpp | 265 ++++++++++++++++----- 12 files changed, 450 insertions(+), 89 deletions(-) create mode 100644 clang/include/clang/Basic/ASTNode.td diff --git a/clang/include/clang/AST/AbstractBasicReader.h b/clang/include/clang/AST/AbstractBasicReader.h index e4e5fe8..b18e89b 100644 --- a/clang/include/clang/AST/AbstractBasicReader.h +++ b/clang/include/clang/AST/AbstractBasicReader.h @@ -37,6 +37,34 @@ inline T *makePointerFromOptional(Optional value) { // where TypeName is the name of a PropertyType node from PropertiesBase.td // and ValueType is the corresponding C++ type name. The read method may // require one or more buffer arguments. +// +// In addition to the concrete type names, BasicReader is expected to +// implement these methods: +// +// template +// Optional writeOptional(); +// +// Reads an optional value from the current property. +// +// template +// ArrayRef readArray(llvm::SmallVectorImpl &buffer); +// +// Reads an array of values from the current property. +// +// PropertyReader readObject(); +// +// Reads an object from the current property; the returned property +// reader will be subjected to a sequence of property reads and then +// discarded before any other properties are reader from the "outer" +// property reader (which need not be the same type). The sub-reader +// will be used as if with the following code: +// +// { +// auto &&widget = W.find("widget").readObject(); +// auto kind = widget.find("kind").readWidgetKind(); +// auto declaration = widget.find("declaration").readDeclRef(); +// return Widget(kind, declaration); +// } // ReadDispatcher does type-based forwarding to one of the read methods // on the BasicReader passed in: @@ -99,6 +127,10 @@ public: return asImpl(); } + // Implement object reading by forwarding to this, collapsing the + // structure into a single data stream. + Impl &readObject() { return asImpl(); } + template llvm::ArrayRef readArray(llvm::SmallVectorImpl &buffer) { assert(buffer.empty()); diff --git a/clang/include/clang/AST/AbstractBasicWriter.h b/clang/include/clang/AST/AbstractBasicWriter.h index a15a49b..499e5a6 100644 --- a/clang/include/clang/AST/AbstractBasicWriter.h +++ b/clang/include/clang/AST/AbstractBasicWriter.h @@ -38,6 +38,33 @@ inline llvm::Optional makeOptionalFromPointer(T *value) { // void write##TypeName(ValueType value); // where TypeName is the name of a PropertyType node from PropertiesBase.td // and ValueType is the corresponding C++ type name. +// +// In addition to the concrete property types, BasicWriter is expected +// to implement these methods: +// +// template +// void writeOptional(Optional value); +// +// Writes an optional value as the current property. +// +// template +// void writeArray(ArrayRef value); +// +// Writes an array of values as the current property. +// +// PropertyWriter writeObject(); +// +// Writes an object as the current property; the returned property +// writer will be subjected to a sequence of property writes and then +// discarded before any other properties are written to the "outer" +// property writer (which need not be the same type). The sub-writer +// will be used as if with the following code: +// +// { +// auto &&widget = W.find("widget").writeObject(); +// widget.find("kind").writeWidgetKind(...); +// widget.find("declaration").writeDeclRef(...); +// } // WriteDispatcher is a template which does type-based forwarding to one // of the write methods of the BasicWriter passed in: @@ -95,6 +122,10 @@ public: return asImpl(); } + // Implement object writing by forwarding to this, collapsing the + // structure into a single data stream. + Impl &writeObject() { return asImpl(); } + template void writeArray(llvm::ArrayRef array) { asImpl().writeUInt32(array.size()); diff --git a/clang/include/clang/AST/PropertiesBase.td b/clang/include/clang/AST/PropertiesBase.td index 7d804e4..cdab032 100644 --- a/clang/include/clang/AST/PropertiesBase.td +++ b/clang/include/clang/AST/PropertiesBase.td @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// -class ASTNode; +class HasProperties; /// The type of the property. class PropertyType { @@ -151,7 +151,7 @@ class Optional : PropertyType { /// A property of an AST node. class Property { - ASTNode Class; + HasProperties Class; string Name = name; PropertyType Type = type; @@ -162,7 +162,7 @@ class Property { /// A rule for creating objects of this type. class Creator { - ASTNode Class; + HasProperties Class; /// A function for creating values of this kind, expressed in terms of a /// variable `ctx` of type `ASTContext &`. Must also refer to all of the @@ -172,8 +172,42 @@ class Creator { /// A rule which overrides some of the normal rules. class Override { - ASTNode Class; + HasProperties Class; /// Properties from base classes that should be ignored. list IgnoredProperties = []; } + +/// A description of how to break a type into cases. Providing this and +/// an exhaustive list of the cases will cause AbstractBasic{Reader,Writer} +/// to be generated with a default implementation of how to read the +/// type. +/// +/// Creator rules for the cases can additionally access a variable +/// `kind` of the KindType. +class PropertyTypeKind { + /// The type for which this describes cases. + PropertyType Type = type; + + /// The type of this type's kind enum. + PropertyType KindType = kindType; + + /// The property name to use for the kind. + string KindPropertyName = "kind"; + + /// An expression which reads the kind from a value, expressed in terms + /// of a variable `node`. + string Read = readCode; +} + +/// One of the options for representing a particular type. +class PropertyTypeCase : HasProperties { + /// The type of which this is a case. + PropertyType Type = type; + + /// The name of the case (a value of the type's kind enum). + string Name = name; +} + diff --git a/clang/include/clang/Basic/ASTNode.td b/clang/include/clang/Basic/ASTNode.td new file mode 100644 index 0000000..61ccc21 --- /dev/null +++ b/clang/include/clang/Basic/ASTNode.td @@ -0,0 +1,8 @@ +#ifndef AST_NODE_TD +#define AST_NODE_TD + +class HasProperties; +class ASTNode : HasProperties; +class AttrSubject; + +#endif diff --git a/clang/include/clang/Basic/CommentNodes.td b/clang/include/clang/Basic/CommentNodes.td index e58ff4c..af2aacc 100644 --- a/clang/include/clang/Basic/CommentNodes.td +++ b/clang/include/clang/Basic/CommentNodes.td @@ -1,4 +1,6 @@ -class CommentNode { +include "clang/Basic/ASTNode.td" + +class CommentNode : ASTNode { CommentNode Base = base; bit Abstract = abstract; } diff --git a/clang/include/clang/Basic/DeclNodes.td b/clang/include/clang/Basic/DeclNodes.td index 7b4c640..c2c2323 100644 --- a/clang/include/clang/Basic/DeclNodes.td +++ b/clang/include/clang/Basic/DeclNodes.td @@ -1,5 +1,4 @@ -class ASTNode; -class AttrSubject; +include "clang/Basic/ASTNode.td" class DeclNode : ASTNode, AttrSubject { diff --git a/clang/include/clang/Basic/StmtNodes.td b/clang/include/clang/Basic/StmtNodes.td index b24199b..2949932 100644 --- a/clang/include/clang/Basic/StmtNodes.td +++ b/clang/include/clang/Basic/StmtNodes.td @@ -1,5 +1,4 @@ -class ASTNode; -class AttrSubject; +include "clang/Basic/ASTNode.td" class StmtNode : ASTNode, AttrSubject { StmtNode Base = base; diff --git a/clang/include/clang/Basic/TypeNodes.td b/clang/include/clang/Basic/TypeNodes.td index 2a08dcc..96d9472 100644 --- a/clang/include/clang/Basic/TypeNodes.td +++ b/clang/include/clang/Basic/TypeNodes.td @@ -1,4 +1,4 @@ -class ASTNode; +include "clang/Basic/ASTNode.td" class TypeNode : ASTNode { TypeNode Base = base; diff --git a/clang/utils/TableGen/ASTTableGen.cpp b/clang/utils/TableGen/ASTTableGen.cpp index c49bcd9..3f6da40 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()) { + return node.getName(); + } else if (auto typeCase = getAs()) { + 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 87934f5..7b7e5f1 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 + 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 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 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 c1bb00b..1cc46cb 100644 --- a/clang/utils/TableGen/ClangASTNodesEmitter.cpp +++ b/clang/utils/TableGen/ClangASTNodesEmitter.cpp @@ -142,7 +142,7 @@ std::pair ClangASTNodesEmitter::EmitNode(raw_ostream &OS, } void ClangASTNodesEmitter::deriveChildTree() { - assert(Root == nullptr && "already computed tree"); + assert(!Root && "already computed tree"); // Emit statements const std::vector Stmts diff --git a/clang/utils/TableGen/ClangASTPropertiesEmitter.cpp b/clang/utils/TableGen/ClangASTPropertiesEmitter.cpp index e14b9eb..81d880c 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 Cases; +}; + class ASTPropsEmitter { raw_ostream &Out; RecordKeeper &Records; - std::map NodeInfos; + std::map NodeInfos; std::vector AllPropertyTypes; + std::map 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 visit) { std::set 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 + visit) { + visit(derivedNode, derivedNodeInfo); + + // Also walk the bases if appropriate. + if (ASTNode base = derivedNode.getAs()) { + 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 - void emitReaderClass() { + void emitNodeReaderClass() { auto info = ReaderWriterInfo::forReader(); - emitReaderWriterClass(info); + emitNodeReaderWriterClass(info); } template - void emitWriterClass() { + void emitNodeWriterClass() { auto info = ReaderWriterInfo::forWriter(); - emitReaderWriterClass(info); + emitNodeReaderWriterClass(info); } template - void emitReaderWriterClass(const ReaderWriterInfo &info); + void emitNodeReaderWriterClass(const ReaderWriterInfo &info); template 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 ValidatedNodes; + ASTPropsEmitter &Emitter; + std::set 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 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 -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(); + ASTPropsEmitter(records, out).emitNodeReaderClass(); } 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(); + ASTPropsEmitter(records, out).emitNodeWriterClass(); } 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); -- 2.7.4