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
|
||||
// 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 <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
|
||||
// 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 <class T>
|
||||
llvm::ArrayRef<T> readArray(llvm::SmallVectorImpl<T> &buffer) {
|
||||
assert(buffer.empty());
|
||||
|
|
|
@ -38,6 +38,33 @@ inline llvm::Optional<T*> 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 <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
|
||||
// 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 <class T>
|
||||
void writeArray(llvm::ArrayRef<T> array) {
|
||||
asImpl().writeUInt32(array.size());
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
class ASTNode;
|
||||
class HasProperties;
|
||||
|
||||
/// The type of the property.
|
||||
class PropertyType<string typeName = ""> {
|
||||
|
@ -151,7 +151,7 @@ class Optional<PropertyType element> : PropertyType {
|
|||
|
||||
/// A property of an AST node.
|
||||
class Property<string name, PropertyType type> {
|
||||
ASTNode Class;
|
||||
HasProperties Class;
|
||||
string Name = name;
|
||||
PropertyType Type = type;
|
||||
|
||||
|
@ -162,7 +162,7 @@ class Property<string name, PropertyType type> {
|
|||
|
||||
/// A rule for creating objects of this type.
|
||||
class Creator<code create> {
|
||||
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<code create> {
|
|||
|
||||
/// A rule which overrides some of the normal rules.
|
||||
class Override {
|
||||
ASTNode Class;
|
||||
HasProperties Class;
|
||||
|
||||
/// Properties from base classes that should be ignored.
|
||||
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;
|
||||
bit Abstract = abstract;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
class ASTNode;
|
||||
class AttrSubject;
|
||||
include "clang/Basic/ASTNode.td"
|
||||
|
||||
class DeclNode<DeclNode base, string diagSpelling = "", bit abstract = 0>
|
||||
: ASTNode, AttrSubject {
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
class ASTNode;
|
||||
class AttrSubject;
|
||||
include "clang/Basic/ASTNode.td"
|
||||
|
||||
class StmtNode<StmtNode base, bit abstract = 0> : ASTNode, AttrSubject {
|
||||
StmtNode Base = base;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
class ASTNode;
|
||||
include "clang/Basic/ASTNode.td"
|
||||
|
||||
class TypeNode<TypeNode base, bit abstract = 0> : ASTNode {
|
||||
TypeNode Base = base;
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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();
|
||||
static llvm::StringRef getTableGenNodeClassName() {
|
||||
return ASTNodeClassName;
|
||||
}
|
||||
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 {
|
||||
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue