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:
John McCall 2019-12-16 02:10:15 -05:00
parent 41d935f2c6
commit efd0dfbd70
12 changed files with 450 additions and 89 deletions

View File

@ -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());

View File

@ -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());

View File

@ -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;
}

View File

@ -0,0 +1,8 @@
#ifndef AST_NODE_TD
#define AST_NODE_TD
class HasProperties;
class ASTNode : HasProperties;
class AttrSubject;
#endif

View File

@ -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;
}

View File

@ -1,5 +1,4 @@
class ASTNode;
class AttrSubject;
include "clang/Basic/ASTNode.td"
class DeclNode<DeclNode base, string diagSpelling = "", bit abstract = 0>
: ASTNode, AttrSubject {

View File

@ -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;

View File

@ -1,4 +1,4 @@
class ASTNode;
include "clang/Basic/ASTNode.td"
class TypeNode<TypeNode base, bit abstract = 0> : ASTNode {
TypeNode Base = base;

View File

@ -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)) {

View File

@ -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

View File

@ -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

View File

@ -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);