forked from OSchip/llvm-project
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.
This commit is contained in:
parent
41d935f2c6
commit
efd0dfbd70
|
@ -37,6 +37,34 @@ inline T *makePointerFromOptional(Optional<T *> value) {
|
||||||
// where TypeName is the name of a PropertyType node from PropertiesBase.td
|
// where TypeName is the name of a PropertyType node from PropertiesBase.td
|
||||||
// and ValueType is the corresponding C++ type name. The read method may
|
// and ValueType is the corresponding C++ type name. The read method may
|
||||||
// require one or more buffer arguments.
|
// require one or more buffer arguments.
|
||||||
|
//
|
||||||
|
// In addition to the concrete type names, BasicReader is expected to
|
||||||
|
// implement these methods:
|
||||||
|
//
|
||||||
|
// template <class ValueType>
|
||||||
|
// Optional<ValueType> writeOptional();
|
||||||
|
//
|
||||||
|
// Reads an optional value from the current property.
|
||||||
|
//
|
||||||
|
// template <class ValueType>
|
||||||
|
// ArrayRef<ValueType> readArray(llvm::SmallVectorImpl<ValueType> &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
|
// ReadDispatcher does type-based forwarding to one of the read methods
|
||||||
// on the BasicReader passed in:
|
// on the BasicReader passed in:
|
||||||
|
@ -99,6 +127,10 @@ public:
|
||||||
return asImpl();
|
return asImpl();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Implement object reading by forwarding to this, collapsing the
|
||||||
|
// structure into a single data stream.
|
||||||
|
Impl &readObject() { return asImpl(); }
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
llvm::ArrayRef<T> readArray(llvm::SmallVectorImpl<T> &buffer) {
|
llvm::ArrayRef<T> readArray(llvm::SmallVectorImpl<T> &buffer) {
|
||||||
assert(buffer.empty());
|
assert(buffer.empty());
|
||||||
|
|
|
@ -38,6 +38,33 @@ inline llvm::Optional<T*> makeOptionalFromPointer(T *value) {
|
||||||
// void write##TypeName(ValueType value);
|
// void write##TypeName(ValueType value);
|
||||||
// where TypeName is the name of a PropertyType node from PropertiesBase.td
|
// where TypeName is the name of a PropertyType node from PropertiesBase.td
|
||||||
// and ValueType is the corresponding C++ type name.
|
// and ValueType is the corresponding C++ type name.
|
||||||
|
//
|
||||||
|
// In addition to the concrete property types, BasicWriter is expected
|
||||||
|
// to implement these methods:
|
||||||
|
//
|
||||||
|
// template <class ValueType>
|
||||||
|
// void writeOptional(Optional<ValueType> value);
|
||||||
|
//
|
||||||
|
// Writes an optional value as the current property.
|
||||||
|
//
|
||||||
|
// template <class ValueType>
|
||||||
|
// void writeArray(ArrayRef<ValueType> 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
|
// WriteDispatcher is a template which does type-based forwarding to one
|
||||||
// of the write methods of the BasicWriter passed in:
|
// of the write methods of the BasicWriter passed in:
|
||||||
|
@ -95,6 +122,10 @@ public:
|
||||||
return asImpl();
|
return asImpl();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Implement object writing by forwarding to this, collapsing the
|
||||||
|
// structure into a single data stream.
|
||||||
|
Impl &writeObject() { return asImpl(); }
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
void writeArray(llvm::ArrayRef<T> array) {
|
void writeArray(llvm::ArrayRef<T> array) {
|
||||||
asImpl().writeUInt32(array.size());
|
asImpl().writeUInt32(array.size());
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
//
|
//
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
class ASTNode;
|
class HasProperties;
|
||||||
|
|
||||||
/// The type of the property.
|
/// The type of the property.
|
||||||
class PropertyType<string typeName = ""> {
|
class PropertyType<string typeName = ""> {
|
||||||
|
@ -151,7 +151,7 @@ class Optional<PropertyType element> : PropertyType {
|
||||||
|
|
||||||
/// A property of an AST node.
|
/// A property of an AST node.
|
||||||
class Property<string name, PropertyType type> {
|
class Property<string name, PropertyType type> {
|
||||||
ASTNode Class;
|
HasProperties Class;
|
||||||
string Name = name;
|
string Name = name;
|
||||||
PropertyType Type = type;
|
PropertyType Type = type;
|
||||||
|
|
||||||
|
@ -162,7 +162,7 @@ class Property<string name, PropertyType type> {
|
||||||
|
|
||||||
/// A rule for creating objects of this type.
|
/// A rule for creating objects of this type.
|
||||||
class Creator<code create> {
|
class Creator<code create> {
|
||||||
ASTNode Class;
|
HasProperties Class;
|
||||||
|
|
||||||
/// A function for creating values of this kind, expressed in terms of a
|
/// 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
|
/// variable `ctx` of type `ASTContext &`. Must also refer to all of the
|
||||||
|
@ -172,8 +172,42 @@ class Creator<code create> {
|
||||||
|
|
||||||
/// A rule which overrides some of the normal rules.
|
/// A rule which overrides some of the normal rules.
|
||||||
class Override {
|
class Override {
|
||||||
ASTNode Class;
|
HasProperties Class;
|
||||||
|
|
||||||
/// Properties from base classes that should be ignored.
|
/// Properties from base classes that should be ignored.
|
||||||
list<string> IgnoredProperties = [];
|
list<string> 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<PropertyType type,
|
||||||
|
PropertyType kindType,
|
||||||
|
string readCode> {
|
||||||
|
/// 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<PropertyType type, string name> : 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
#ifndef AST_NODE_TD
|
||||||
|
#define AST_NODE_TD
|
||||||
|
|
||||||
|
class HasProperties;
|
||||||
|
class ASTNode : HasProperties;
|
||||||
|
class AttrSubject;
|
||||||
|
|
||||||
|
#endif
|
|
@ -1,4 +1,6 @@
|
||||||
class CommentNode<CommentNode base, bit abstract = 0> {
|
include "clang/Basic/ASTNode.td"
|
||||||
|
|
||||||
|
class CommentNode<CommentNode base, bit abstract = 0> : ASTNode {
|
||||||
CommentNode Base = base;
|
CommentNode Base = base;
|
||||||
bit Abstract = abstract;
|
bit Abstract = abstract;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
class ASTNode;
|
include "clang/Basic/ASTNode.td"
|
||||||
class AttrSubject;
|
|
||||||
|
|
||||||
class DeclNode<DeclNode base, string diagSpelling = "", bit abstract = 0>
|
class DeclNode<DeclNode base, string diagSpelling = "", bit abstract = 0>
|
||||||
: ASTNode, AttrSubject {
|
: ASTNode, AttrSubject {
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
class ASTNode;
|
include "clang/Basic/ASTNode.td"
|
||||||
class AttrSubject;
|
|
||||||
|
|
||||||
class StmtNode<StmtNode base, bit abstract = 0> : ASTNode, AttrSubject {
|
class StmtNode<StmtNode base, bit abstract = 0> : ASTNode, AttrSubject {
|
||||||
StmtNode Base = base;
|
StmtNode Base = base;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
class ASTNode;
|
include "clang/Basic/ASTNode.td"
|
||||||
|
|
||||||
class TypeNode<TypeNode base, bit abstract = 0> : ASTNode {
|
class TypeNode<TypeNode base, bit abstract = 0> : ASTNode {
|
||||||
TypeNode Base = base;
|
TypeNode Base = base;
|
||||||
|
|
|
@ -20,6 +20,16 @@ using namespace llvm;
|
||||||
using namespace clang;
|
using namespace clang;
|
||||||
using namespace clang::tblgen;
|
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) {
|
static StringRef removeExpectedNodeNameSuffix(Record *node, StringRef suffix) {
|
||||||
StringRef nodeName = node->getName();
|
StringRef nodeName = node->getName();
|
||||||
if (!nodeName.endswith(suffix)) {
|
if (!nodeName.endswith(suffix)) {
|
||||||
|
|
|
@ -14,7 +14,11 @@
|
||||||
|
|
||||||
// These are spellings in the tblgen files.
|
// 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 BaseFieldName "Base"
|
||||||
#define AbstractFieldName "Abstract"
|
#define AbstractFieldName "Abstract"
|
||||||
|
|
||||||
|
@ -35,6 +39,12 @@
|
||||||
#define NeverCanonicalUnlessDependentClassName "NeverCanonicalUnlessDependent"
|
#define NeverCanonicalUnlessDependentClassName "NeverCanonicalUnlessDependent"
|
||||||
#define LeafTypeClassName "LeafType"
|
#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.
|
// Properties of AST nodes.
|
||||||
#define PropertyClassName "Property"
|
#define PropertyClassName "Property"
|
||||||
#define ClassFieldName "Class"
|
#define ClassFieldName "Class"
|
||||||
|
@ -94,13 +104,54 @@ public:
|
||||||
bool isSubClassOf(llvm::StringRef className) const {
|
bool isSubClassOf(llvm::StringRef className) const {
|
||||||
return get()->isSubClassOf(className);
|
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
|
/// An (optional) reference to a TableGen node representing a class
|
||||||
/// in one of Clang's AST hierarchies.
|
/// in one of Clang's AST hierarchies.
|
||||||
class ASTNode : public WrappedRecord {
|
class ASTNode : public HasProperties {
|
||||||
public:
|
public:
|
||||||
ASTNode(llvm::Record *record = nullptr) : WrappedRecord(record) {}
|
ASTNode(llvm::Record *record = nullptr) : HasProperties(record) {}
|
||||||
|
|
||||||
llvm::StringRef getName() const {
|
llvm::StringRef getName() const {
|
||||||
return get()->getName();
|
return get()->getName();
|
||||||
|
@ -116,19 +167,9 @@ public:
|
||||||
return get()->getValueAsBit(AbstractFieldName);
|
return get()->getValueAsBit(AbstractFieldName);
|
||||||
}
|
}
|
||||||
|
|
||||||
friend bool operator<(ASTNode lhs, ASTNode rhs) {
|
static llvm::StringRef getTableGenNodeClassName() {
|
||||||
assert(lhs && rhs && "sorting null nodes");
|
return ASTNodeClassName;
|
||||||
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();
|
|
||||||
}
|
|
||||||
friend bool operator!=(ASTNode lhs, ASTNode rhs) { return !(lhs == rhs); }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class DeclNode : public ASTNode {
|
class DeclNode : public ASTNode {
|
||||||
|
@ -275,6 +316,60 @@ public:
|
||||||
std::vector<llvm::Record*> getBufferElementTypes() const {
|
std::vector<llvm::Record*> getBufferElementTypes() const {
|
||||||
return get()->getValueAsListOfDefs(BufferElementTypesFieldName);
|
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.
|
/// A property of an AST node.
|
||||||
|
@ -301,6 +396,10 @@ public:
|
||||||
llvm::StringRef getReadCode() const {
|
llvm::StringRef getReadCode() const {
|
||||||
return get()->getValueAsString(ReadFieldName);
|
return get()->getValueAsString(ReadFieldName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static llvm::StringRef getTableGenNodeClassName() {
|
||||||
|
return PropertyClassName;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A rule for how to create an AST node from its properties.
|
/// A rule for how to create an AST node from its properties.
|
||||||
|
@ -317,6 +416,10 @@ public:
|
||||||
llvm::StringRef getCreationCode() const {
|
llvm::StringRef getCreationCode() const {
|
||||||
return get()->getValueAsString(CreateFieldName);
|
return get()->getValueAsString(CreateFieldName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static llvm::StringRef getTableGenNodeClassName() {
|
||||||
|
return CreationRuleClassName;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A rule which overrides the standard rules for serializing an AST node.
|
/// A rule which overrides the standard rules for serializing an AST node.
|
||||||
|
@ -336,6 +439,10 @@ public:
|
||||||
std::vector<llvm::StringRef> getIgnoredProperties() const {
|
std::vector<llvm::StringRef> getIgnoredProperties() const {
|
||||||
return get()->getValueAsListOfStrings(IgnoredPropertiesFieldName);
|
return get()->getValueAsListOfStrings(IgnoredPropertiesFieldName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static llvm::StringRef getTableGenNodeClassName() {
|
||||||
|
return OverrideRuleClassName;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A visitor for an AST node hierarchy. Note that `base` can be null for
|
/// A visitor for an AST node hierarchy. Note that `base` can be null for
|
||||||
|
|
|
@ -142,7 +142,7 @@ std::pair<ASTNode, ASTNode> ClangASTNodesEmitter::EmitNode(raw_ostream &OS,
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClangASTNodesEmitter::deriveChildTree() {
|
void ClangASTNodesEmitter::deriveChildTree() {
|
||||||
assert(Root == nullptr && "already computed tree");
|
assert(!Root && "already computed tree");
|
||||||
|
|
||||||
// Emit statements
|
// Emit statements
|
||||||
const std::vector<Record*> Stmts
|
const std::vector<Record*> Stmts
|
||||||
|
|
|
@ -80,11 +80,17 @@ struct NodeInfo {
|
||||||
OverrideRule Override = nullptr;
|
OverrideRule Override = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct CasedTypeInfo {
|
||||||
|
TypeKindRule KindRule;
|
||||||
|
std::vector<TypeCase> Cases;
|
||||||
|
};
|
||||||
|
|
||||||
class ASTPropsEmitter {
|
class ASTPropsEmitter {
|
||||||
raw_ostream &Out;
|
raw_ostream &Out;
|
||||||
RecordKeeper &Records;
|
RecordKeeper &Records;
|
||||||
std::map<ASTNode, NodeInfo> NodeInfos;
|
std::map<HasProperties, NodeInfo> NodeInfos;
|
||||||
std::vector<PropertyType> AllPropertyTypes;
|
std::vector<PropertyType> AllPropertyTypes;
|
||||||
|
std::map<PropertyType, CasedTypeInfo> CasedTypeInfos;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ASTPropsEmitter(RecordKeeper &records, raw_ostream &out)
|
ASTPropsEmitter(RecordKeeper &records, raw_ostream &out)
|
||||||
|
@ -125,6 +131,7 @@ public:
|
||||||
info.Override = overrideRule;
|
info.Override = overrideRule;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Find all the concrete property types.
|
||||||
for (PropertyType type :
|
for (PropertyType type :
|
||||||
records.getAllDerivedDefinitions(PropertyTypeClassName)) {
|
records.getAllDerivedDefinitions(PropertyTypeClassName)) {
|
||||||
// Ignore generic specializations; they're generally not useful when
|
// Ignore generic specializations; they're generally not useful when
|
||||||
|
@ -134,10 +141,29 @@ public:
|
||||||
AllPropertyTypes.push_back(type);
|
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();
|
Validator(*this).validate();
|
||||||
}
|
}
|
||||||
|
|
||||||
void visitAllProperties(ASTNode derived, const NodeInfo &derivedInfo,
|
void visitAllProperties(HasProperties derived, const NodeInfo &derivedInfo,
|
||||||
function_ref<void (Property)> visit) {
|
function_ref<void (Property)> visit) {
|
||||||
std::set<StringRef> ignoredProperties;
|
std::set<StringRef> ignoredProperties;
|
||||||
|
|
||||||
|
@ -147,60 +173,88 @@ public:
|
||||||
ignoredProperties.insert(list.begin(), list.end());
|
ignoredProperties.insert(list.begin(), list.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
for (ASTNode node = derived; node; node = node.getBase()) {
|
visitAllNodesWithInfo(derived, derivedInfo,
|
||||||
auto it = NodeInfos.find(node);
|
[&](HasProperties node, const NodeInfo &info) {
|
||||||
|
|
||||||
// Ignore intermediate nodes that don't add interesting properties.
|
|
||||||
if (it == NodeInfos.end()) continue;
|
|
||||||
auto &info = it->second;
|
|
||||||
|
|
||||||
for (Property prop : info.Properties) {
|
for (Property prop : info.Properties) {
|
||||||
if (ignoredProperties.count(prop.getName()))
|
if (ignoredProperties.count(prop.getName()))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
visit(prop);
|
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>
|
template <class NodeClass>
|
||||||
void emitReaderClass() {
|
void emitNodeReaderClass() {
|
||||||
auto info = ReaderWriterInfo::forReader<NodeClass>();
|
auto info = ReaderWriterInfo::forReader<NodeClass>();
|
||||||
emitReaderWriterClass<NodeClass>(info);
|
emitNodeReaderWriterClass<NodeClass>(info);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class NodeClass>
|
template <class NodeClass>
|
||||||
void emitWriterClass() {
|
void emitNodeWriterClass() {
|
||||||
auto info = ReaderWriterInfo::forWriter<NodeClass>();
|
auto info = ReaderWriterInfo::forWriter<NodeClass>();
|
||||||
emitReaderWriterClass<NodeClass>(info);
|
emitNodeReaderWriterClass<NodeClass>(info);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class NodeClass>
|
template <class NodeClass>
|
||||||
void emitReaderWriterClass(const ReaderWriterInfo &info);
|
void emitNodeReaderWriterClass(const ReaderWriterInfo &info);
|
||||||
|
|
||||||
template <class NodeClass>
|
template <class NodeClass>
|
||||||
void emitNodeReaderWriterMethod(NodeClass node,
|
void emitNodeReaderWriterMethod(NodeClass node,
|
||||||
const ReaderWriterInfo &info);
|
const ReaderWriterInfo &info);
|
||||||
|
|
||||||
void emitReadOfProperty(Property property);
|
void emitPropertiedReaderWriterBody(HasProperties node,
|
||||||
void emitWriteOfProperty(Property property);
|
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 emitBasicReaderWriterFile(const ReaderWriterInfo &info);
|
||||||
void emitDispatcherTemplate(const ReaderWriterInfo &info);
|
void emitDispatcherTemplate(const ReaderWriterInfo &info);
|
||||||
void emitPackUnpackOptionalTemplate(const ReaderWriterInfo &info);
|
void emitPackUnpackOptionalTemplate(const ReaderWriterInfo &info);
|
||||||
void emitBasicReaderWriterTemplate(const ReaderWriterInfo &info);
|
void emitBasicReaderWriterTemplate(const ReaderWriterInfo &info);
|
||||||
|
|
||||||
|
void emitCasedReaderWriterMethodBody(PropertyType type,
|
||||||
|
const CasedTypeInfo &typeCases,
|
||||||
|
const ReaderWriterInfo &info);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
class Validator {
|
class Validator {
|
||||||
const ASTPropsEmitter &Emitter;
|
ASTPropsEmitter &Emitter;
|
||||||
std::set<ASTNode> ValidatedNodes;
|
std::set<HasProperties> ValidatedNodes;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Validator(const ASTPropsEmitter &emitter) : Emitter(emitter) {}
|
Validator(ASTPropsEmitter &emitter) : Emitter(emitter) {}
|
||||||
void validate();
|
void validate();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void validateNode(ASTNode node, const NodeInfo &nodeInfo);
|
void validateNode(HasProperties node, const NodeInfo &nodeInfo);
|
||||||
void validateType(PropertyType type, WrappedRecord context);
|
void validateType(PropertyType type, WrappedRecord context);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -217,21 +271,17 @@ void ASTPropsEmitter::Validator::validate() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ASTPropsEmitter::Validator::validateNode(ASTNode node,
|
void ASTPropsEmitter::Validator::validateNode(HasProperties derivedNode,
|
||||||
const NodeInfo &nodeInfo) {
|
const NodeInfo &derivedNodeInfo) {
|
||||||
if (!ValidatedNodes.insert(node).second) return;
|
if (!ValidatedNodes.insert(derivedNode).second) return;
|
||||||
|
|
||||||
// A map from property name to property.
|
// A map from property name to property.
|
||||||
std::map<StringRef, Property> allProperties;
|
std::map<StringRef, Property> allProperties;
|
||||||
|
|
||||||
// Walk the hierarchy, ignoring nodes that don't declare anything
|
Emitter.visitAllNodesWithInfo(derivedNode, derivedNodeInfo,
|
||||||
// interesting.
|
[&](HasProperties node,
|
||||||
for (auto base = node; base; base = base.getBase()) {
|
const NodeInfo &nodeInfo) {
|
||||||
auto it = Emitter.NodeInfos.find(base);
|
for (Property property : nodeInfo.Properties) {
|
||||||
if (it == Emitter.NodeInfos.end()) continue;
|
|
||||||
|
|
||||||
auto &baseInfo = it->second;
|
|
||||||
for (Property property : baseInfo.Properties) {
|
|
||||||
validateType(property.getType(), property);
|
validateType(property.getType(), property);
|
||||||
|
|
||||||
auto result = allProperties.insert(
|
auto result = allProperties.insert(
|
||||||
|
@ -244,11 +294,11 @@ void ASTPropsEmitter::Validator::validateNode(ASTNode node,
|
||||||
Property existingProperty = result.first->second;
|
Property existingProperty = result.first->second;
|
||||||
PrintError(existingProperty.getLoc(),
|
PrintError(existingProperty.getLoc(),
|
||||||
"multiple properties named \"" + property.getName()
|
"multiple properties named \"" + property.getName()
|
||||||
+ "\" in hierarchy of " + node.getName());
|
+ "\" in hierarchy of " + derivedNode.getName());
|
||||||
PrintNote(property.getLoc(), "existing property");
|
PrintNote(property.getLoc(), "existing property");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void ASTPropsEmitter::Validator::validateType(PropertyType type,
|
void ASTPropsEmitter::Validator::validateType(PropertyType type,
|
||||||
|
@ -284,7 +334,7 @@ void ASTPropsEmitter::Validator::validateType(PropertyType type,
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
template <class NodeClass>
|
template <class NodeClass>
|
||||||
void ASTPropsEmitter::emitReaderWriterClass(const ReaderWriterInfo &info) {
|
void ASTPropsEmitter::emitNodeReaderWriterClass(const ReaderWriterInfo &info) {
|
||||||
StringRef suffix = info.ClassSuffix;
|
StringRef suffix = info.ClassSuffix;
|
||||||
StringRef var = info.HelperVariable;
|
StringRef var = info.HelperVariable;
|
||||||
|
|
||||||
|
@ -350,6 +400,14 @@ void ASTPropsEmitter::emitNodeReaderWriterMethod(NodeClass node,
|
||||||
if (info.IsReader)
|
if (info.IsReader)
|
||||||
Out << " auto &ctx = " << info.HelperVariable << ".getASTContext();\n";
|
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.
|
// Find the information for this node.
|
||||||
auto it = NodeInfos.find(node);
|
auto it = NodeInfos.find(node);
|
||||||
if (it == NodeInfos.end())
|
if (it == NodeInfos.end())
|
||||||
|
@ -380,17 +438,14 @@ void ASTPropsEmitter::emitNodeReaderWriterMethod(NodeClass node,
|
||||||
|
|
||||||
// Emit code to read or write this property.
|
// Emit code to read or write this property.
|
||||||
if (info.IsReader)
|
if (info.IsReader)
|
||||||
emitReadOfProperty(prop);
|
emitReadOfProperty(info.HelperVariable, prop);
|
||||||
else
|
else
|
||||||
emitWriteOfProperty(prop);
|
emitWriteOfProperty(info.HelperVariable, prop);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Emit the final creation code.
|
// Emit the final creation code.
|
||||||
if (info.IsReader)
|
if (info.IsReader)
|
||||||
Out << " " << creationCode << "\n";
|
Out << " " << creationCode << "\n";
|
||||||
|
|
||||||
// Finish the method declaration.
|
|
||||||
Out << " }\n\n";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void emitBasicReaderWriterMethodSuffix(raw_ostream &out,
|
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.
|
/// Emit code to read the given property in a node-reader method.
|
||||||
void ASTPropsEmitter::emitReadOfProperty(Property property) {
|
void ASTPropsEmitter::emitReadOfProperty(StringRef readerName,
|
||||||
PropertyType type = property.getType();
|
Property property) {
|
||||||
auto name = property.getName();
|
emitReadOfProperty(readerName, property.getName(), property.getType());
|
||||||
|
}
|
||||||
|
|
||||||
|
void ASTPropsEmitter::emitReadOfProperty(StringRef readerName,
|
||||||
|
StringRef name,
|
||||||
|
PropertyType type) {
|
||||||
// Declare all the necessary buffers.
|
// Declare all the necessary buffers.
|
||||||
auto bufferTypes = type.getBufferElementTypes();
|
auto bufferTypes = type.getBufferElementTypes();
|
||||||
for (size_t i = 0, e = bufferTypes.size(); i != e; ++i) {
|
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.
|
// that in the creation rule.
|
||||||
Out << " ";
|
Out << " ";
|
||||||
type.emitCXXValueTypeName(true, Out);
|
type.emitCXXValueTypeName(true, Out);
|
||||||
Out << " " << name << " = R.find(\"" << name << "\")."
|
Out << " " << name << " = " << readerName << ".find(\"" << name << "\")."
|
||||||
<< (type.isGenericSpecialization() ? "template " : "") << "read";
|
<< (type.isGenericSpecialization() ? "template " : "") << "read";
|
||||||
emitBasicReaderWriterMethodSuffix(Out, type, /*for read*/ true);
|
emitBasicReaderWriterMethodSuffix(Out, type, /*for read*/ true);
|
||||||
Out << "(";
|
Out << "(";
|
||||||
|
@ -451,13 +510,21 @@ void ASTPropsEmitter::emitReadOfProperty(Property property) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Emit code to write the given property in a node-writer method.
|
/// 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:
|
// Focus down to the property:
|
||||||
// W.find("prop").write##ValueType(value);
|
// W.find("prop").write##ValueType(value);
|
||||||
Out << " W.find(\"" << property.getName() << "\").write";
|
Out << " " << writerName << ".find(\"" << name << "\").write";
|
||||||
emitBasicReaderWriterMethodSuffix(Out, property.getType(),
|
emitBasicReaderWriterMethodSuffix(Out, type, /*for read*/ false);
|
||||||
/*for read*/ false);
|
Out << "(" << readCode << ");\n";
|
||||||
Out << "(" << property.getReadCode() << ");\n";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Emit an .inc file that defines the AbstractFooReader class
|
/// Emit an .inc file that defines the AbstractFooReader class
|
||||||
|
@ -467,7 +534,7 @@ static void emitASTReader(RecordKeeper &records, raw_ostream &out,
|
||||||
StringRef description) {
|
StringRef description) {
|
||||||
emitSourceFileHeader(description, out);
|
emitSourceFileHeader(description, out);
|
||||||
|
|
||||||
ASTPropsEmitter(records, out).emitReaderClass<NodeClass>();
|
ASTPropsEmitter(records, out).emitNodeReaderClass<NodeClass>();
|
||||||
}
|
}
|
||||||
|
|
||||||
void clang::EmitClangTypeReader(RecordKeeper &records, raw_ostream &out) {
|
void clang::EmitClangTypeReader(RecordKeeper &records, raw_ostream &out) {
|
||||||
|
@ -481,7 +548,7 @@ static void emitASTWriter(RecordKeeper &records, raw_ostream &out,
|
||||||
StringRef description) {
|
StringRef description) {
|
||||||
emitSourceFileHeader(description, out);
|
emitSourceFileHeader(description, out);
|
||||||
|
|
||||||
ASTPropsEmitter(records, out).emitWriterClass<NodeClass>();
|
ASTPropsEmitter(records, out).emitNodeWriterClass<NodeClass>();
|
||||||
}
|
}
|
||||||
|
|
||||||
void clang::EmitClangTypeWriter(RecordKeeper &records, raw_ostream &out) {
|
void clang::EmitClangTypeWriter(RecordKeeper &records, raw_ostream &out) {
|
||||||
|
@ -596,35 +663,49 @@ ASTPropsEmitter::emitBasicReaderWriterTemplate(const ReaderWriterInfo &info) {
|
||||||
auto enterReaderWriterMethod = [&](StringRef cxxTypeName,
|
auto enterReaderWriterMethod = [&](StringRef cxxTypeName,
|
||||||
StringRef abstractTypeName,
|
StringRef abstractTypeName,
|
||||||
bool shouldPassByReference,
|
bool shouldPassByReference,
|
||||||
bool constWhenWriting) {
|
bool constWhenWriting,
|
||||||
|
StringRef paramName) {
|
||||||
Out << " " << (info.IsReader ? cxxTypeName : "void")
|
Out << " " << (info.IsReader ? cxxTypeName : "void")
|
||||||
<< " " << info.MethodPrefix << abstractTypeName << "(";
|
<< " " << info.MethodPrefix << abstractTypeName << "(";
|
||||||
if (!info.IsReader)
|
if (!info.IsReader)
|
||||||
Out << (shouldPassByReference || constWhenWriting ? "const " : "")
|
Out << (shouldPassByReference || constWhenWriting ? "const " : "")
|
||||||
<< cxxTypeName
|
<< cxxTypeName
|
||||||
<< (shouldPassByReference ? " &" : "") << " value";
|
<< (shouldPassByReference ? " &" : "") << " " << paramName;
|
||||||
Out << ") {\n";
|
Out << ") {\n";
|
||||||
};
|
};
|
||||||
|
|
||||||
// Emit {read,write}ValueType methods for all the enum and subclass types
|
// Emit {read,write}ValueType methods for all the enum and subclass types
|
||||||
// that default to using the integer/base-class implementations.
|
// that default to using the integer/base-class implementations.
|
||||||
for (PropertyType type : AllPropertyTypes) {
|
for (PropertyType type : AllPropertyTypes) {
|
||||||
if (type.isEnum()) {
|
auto enterMethod = [&](StringRef paramName) {
|
||||||
enterReaderWriterMethod(type.getCXXTypeName(),
|
enterReaderWriterMethod(type.getCXXTypeName(),
|
||||||
type.getAbstractTypeName(),
|
type.getAbstractTypeName(),
|
||||||
/*pass by reference*/ false,
|
type.shouldPassByReference(),
|
||||||
/*const when writing*/ false);
|
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)
|
if (info.IsReader)
|
||||||
Out << " return " << type.getCXXTypeName()
|
Out << " return " << type.getCXXTypeName()
|
||||||
<< "(asImpl().readUInt32());\n";
|
<< "(asImpl().readUInt32());\n";
|
||||||
else
|
else
|
||||||
Out << " asImpl().writeUInt32(uint32_t(value));\n";
|
Out << " asImpl().writeUInt32(uint32_t(value));\n";
|
||||||
Out << " }\n";
|
exitMethod();
|
||||||
|
|
||||||
} else if (PropertyType superclass = type.getSuperclassType()) {
|
} else if (PropertyType superclass = type.getSuperclassType()) {
|
||||||
enterReaderWriterMethod(type.getCXXTypeName(),
|
enterMethod("value");
|
||||||
type.getAbstractTypeName(),
|
|
||||||
/*pass by reference*/ false,
|
|
||||||
/*const when writing*/ type.isConstWhenWriting());
|
|
||||||
if (info.IsReader)
|
if (info.IsReader)
|
||||||
Out << " return cast_or_null<" << type.getSubclassClassName()
|
Out << " return cast_or_null<" << type.getSubclassClassName()
|
||||||
<< ">(asImpl().read"
|
<< ">(asImpl().read"
|
||||||
|
@ -633,7 +714,8 @@ ASTPropsEmitter::emitBasicReaderWriterTemplate(const ReaderWriterInfo &info) {
|
||||||
else
|
else
|
||||||
Out << " asImpl().write" << superclass.getAbstractTypeName()
|
Out << " asImpl().write" << superclass.getAbstractTypeName()
|
||||||
<< "(value);\n";
|
<< "(value);\n";
|
||||||
Out << " }\n";
|
exitMethod();
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// The other types can't be handled as trivially.
|
// The other types can't be handled as trivially.
|
||||||
}
|
}
|
||||||
|
@ -641,9 +723,66 @@ ASTPropsEmitter::emitBasicReaderWriterTemplate(const ReaderWriterInfo &info) {
|
||||||
Out << "};\n\n";
|
Out << "};\n\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
void ASTPropsEmitter::emitBasicReaderWriterFile(const ReaderWriterInfo &info) {
|
void ASTPropsEmitter::emitCasedReaderWriterMethodBody(PropertyType type,
|
||||||
auto types = Records.getAllDerivedDefinitions(PropertyTypeClassName);
|
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);
|
emitDispatcherTemplate(info);
|
||||||
emitPackUnpackOptionalTemplate(info);
|
emitPackUnpackOptionalTemplate(info);
|
||||||
emitBasicReaderWriterTemplate(info);
|
emitBasicReaderWriterTemplate(info);
|
||||||
|
|
Loading…
Reference in New Issue