123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870 |
- //=== ClangASTPropsEmitter.cpp - Generate Clang AST properties --*- C++ -*-===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- //
- // This tablegen backend emits code for working with Clang AST properties.
- //
- //===----------------------------------------------------------------------===//
- #include "ASTTableGen.h"
- #include "TableGenBackends.h"
- #include "llvm/ADT/STLExtras.h"
- #include "llvm/ADT/Twine.h"
- #include "llvm/TableGen/Error.h"
- #include "llvm/TableGen/Record.h"
- #include "llvm/TableGen/TableGenBackend.h"
- #include <cctype>
- #include <map>
- #include <optional>
- #include <set>
- #include <string>
- using namespace llvm;
- using namespace clang;
- using namespace clang::tblgen;
- static StringRef getReaderResultType(TypeNode _) { return "QualType"; }
- namespace {
- struct ReaderWriterInfo {
- bool IsReader;
- /// The name of the node hierarchy. Not actually sensitive to IsReader,
- /// but useful to cache here anyway.
- StringRef HierarchyName;
- /// The suffix on classes: Reader/Writer
- StringRef ClassSuffix;
- /// The base name of methods: read/write
- StringRef MethodPrefix;
- /// The name of the property helper member: R/W
- StringRef HelperVariable;
- /// The result type of methods on the class.
- StringRef ResultType;
- template <class NodeClass>
- static ReaderWriterInfo forReader() {
- return ReaderWriterInfo{
- true,
- NodeClass::getASTHierarchyName(),
- "Reader",
- "read",
- "R",
- getReaderResultType(NodeClass())
- };
- }
- template <class NodeClass>
- static ReaderWriterInfo forWriter() {
- return ReaderWriterInfo{
- false,
- NodeClass::getASTHierarchyName(),
- "Writer",
- "write",
- "W",
- "void"
- };
- }
- };
- struct NodeInfo {
- std::vector<Property> Properties;
- CreationRule Creator = nullptr;
- OverrideRule Override = nullptr;
- ReadHelperRule ReadHelper = nullptr;
- };
- struct CasedTypeInfo {
- TypeKindRule KindRule;
- std::vector<TypeCase> Cases;
- };
- class ASTPropsEmitter {
- raw_ostream &Out;
- RecordKeeper &Records;
- std::map<HasProperties, NodeInfo> NodeInfos;
- std::vector<PropertyType> AllPropertyTypes;
- std::map<PropertyType, CasedTypeInfo> CasedTypeInfos;
- public:
- ASTPropsEmitter(RecordKeeper &records, raw_ostream &out)
- : Out(out), Records(records) {
- // Find all the properties.
- for (Property property :
- records.getAllDerivedDefinitions(PropertyClassName)) {
- HasProperties node = property.getClass();
- NodeInfos[node].Properties.push_back(property);
- }
- // Find all the creation rules.
- for (CreationRule creationRule :
- records.getAllDerivedDefinitions(CreationRuleClassName)) {
- HasProperties node = creationRule.getClass();
- auto &info = NodeInfos[node];
- if (info.Creator) {
- PrintFatalError(creationRule.getLoc(),
- "multiple creator rules for \"" + node.getName()
- + "\"");
- }
- info.Creator = creationRule;
- }
- // Find all the override rules.
- for (OverrideRule overrideRule :
- records.getAllDerivedDefinitions(OverrideRuleClassName)) {
- HasProperties node = overrideRule.getClass();
- auto &info = NodeInfos[node];
- if (info.Override) {
- PrintFatalError(overrideRule.getLoc(),
- "multiple override rules for \"" + node.getName()
- + "\"");
- }
- info.Override = overrideRule;
- }
- // Find all the write helper rules.
- for (ReadHelperRule helperRule :
- records.getAllDerivedDefinitions(ReadHelperRuleClassName)) {
- HasProperties node = helperRule.getClass();
- auto &info = NodeInfos[node];
- if (info.ReadHelper) {
- PrintFatalError(helperRule.getLoc(),
- "multiple write helper rules for \"" + node.getName()
- + "\"");
- }
- info.ReadHelper = helperRule;
- }
- // Find all the concrete property types.
- for (PropertyType type :
- records.getAllDerivedDefinitions(PropertyTypeClassName)) {
- // Ignore generic specializations; they're generally not useful when
- // emitting basic emitters etc.
- if (type.isGenericSpecialization()) continue;
- 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(HasProperties derived, const NodeInfo &derivedInfo,
- function_ref<void (Property)> visit) {
- std::set<StringRef> ignoredProperties;
- auto overrideRule = derivedInfo.Override;
- if (overrideRule) {
- auto list = overrideRule.getIgnoredProperties();
- ignoredProperties.insert(list.begin(), list.end());
- }
- // TODO: we should sort the properties in various ways
- // - put arrays at the end to enable abbreviations
- // - put conditional properties after properties used in the condition
- 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 emitNodeReaderClass() {
- auto info = ReaderWriterInfo::forReader<NodeClass>();
- emitNodeReaderWriterClass<NodeClass>(info);
- }
- template <class NodeClass>
- void emitNodeWriterClass() {
- auto info = ReaderWriterInfo::forWriter<NodeClass>();
- emitNodeReaderWriterClass<NodeClass>(info);
- }
- template <class NodeClass>
- void emitNodeReaderWriterClass(const ReaderWriterInfo &info);
- template <class NodeClass>
- void emitNodeReaderWriterMethod(NodeClass node,
- const ReaderWriterInfo &info);
- void emitPropertiedReaderWriterBody(HasProperties node,
- const ReaderWriterInfo &info);
- void emitReadOfProperty(StringRef readerName, Property property);
- void emitReadOfProperty(StringRef readerName, StringRef name,
- PropertyType type, StringRef condition = "");
- void emitWriteOfProperty(StringRef writerName, Property property);
- void emitWriteOfProperty(StringRef writerName, StringRef name,
- PropertyType type, StringRef readCode,
- StringRef condition = "");
- 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 {
- ASTPropsEmitter &Emitter;
- std::set<HasProperties> ValidatedNodes;
- public:
- Validator(ASTPropsEmitter &emitter) : Emitter(emitter) {}
- void validate();
- private:
- void validateNode(HasProperties node, const NodeInfo &nodeInfo);
- void validateType(PropertyType type, WrappedRecord context);
- };
- };
- } // end anonymous namespace
- void ASTPropsEmitter::Validator::validate() {
- for (auto &entry : Emitter.NodeInfos) {
- validateNode(entry.first, entry.second);
- }
- if (ErrorsPrinted > 0) {
- PrintFatalError("property validation failed");
- }
- }
- 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;
- Emitter.visitAllNodesWithInfo(derivedNode, derivedNodeInfo,
- [&](HasProperties node,
- const NodeInfo &nodeInfo) {
- for (Property property : nodeInfo.Properties) {
- validateType(property.getType(), property);
- auto result = allProperties.insert(
- std::make_pair(property.getName(), property));
- // Diagnose non-unique properties.
- if (!result.second) {
- // The existing property is more likely to be associated with a
- // derived node, so use it as the error.
- Property existingProperty = result.first->second;
- PrintError(existingProperty.getLoc(),
- "multiple properties named \"" + property.getName()
- + "\" in hierarchy of " + derivedNode.getName());
- PrintNote(property.getLoc(), "existing property");
- }
- }
- });
- }
- void ASTPropsEmitter::Validator::validateType(PropertyType type,
- WrappedRecord context) {
- if (!type.isGenericSpecialization()) {
- if (type.getCXXTypeName() == "") {
- PrintError(type.getLoc(),
- "type is not generic but has no C++ type name");
- if (context) PrintNote(context.getLoc(), "type used here");
- }
- } else if (auto eltType = type.getArrayElementType()) {
- validateType(eltType, context);
- } else if (auto valueType = type.getOptionalElementType()) {
- validateType(valueType, context);
- if (valueType.getPackOptionalCode().empty()) {
- PrintError(valueType.getLoc(),
- "type doesn't provide optional-packing code");
- if (context) PrintNote(context.getLoc(), "type used here");
- } else if (valueType.getUnpackOptionalCode().empty()) {
- PrintError(valueType.getLoc(),
- "type doesn't provide optional-unpacking code");
- if (context) PrintNote(context.getLoc(), "type used here");
- }
- } else {
- PrintError(type.getLoc(), "unknown generic property type");
- if (context) PrintNote(context.getLoc(), "type used here");
- }
- }
- /****************************************************************************/
- /**************************** AST READER/WRITERS ****************************/
- /****************************************************************************/
- template <class NodeClass>
- void ASTPropsEmitter::emitNodeReaderWriterClass(const ReaderWriterInfo &info) {
- StringRef suffix = info.ClassSuffix;
- StringRef var = info.HelperVariable;
- // Enter the class declaration.
- Out << "template <class Property" << suffix << ">\n"
- "class Abstract" << info.HierarchyName << suffix << " {\n"
- "public:\n"
- " Property" << suffix << " &" << var << ";\n\n";
- // Emit the constructor.
- Out << " Abstract" << info.HierarchyName << suffix
- << "(Property" << suffix << " &" << var << ") : "
- << var << "(" << var << ") {}\n\n";
- // Emit a method that dispatches on a kind to the appropriate node-specific
- // method.
- Out << " " << info.ResultType << " " << info.MethodPrefix << "(";
- if (info.IsReader)
- Out << NodeClass::getASTIdTypeName() << " kind";
- else
- Out << "const " << info.HierarchyName << " *node";
- Out << ") {\n"
- " switch (";
- if (info.IsReader)
- Out << "kind";
- else
- Out << "node->" << NodeClass::getASTIdAccessorName() << "()";
- Out << ") {\n";
- visitASTNodeHierarchy<NodeClass>(Records, [&](NodeClass node, NodeClass _) {
- if (node.isAbstract()) return;
- Out << " case " << info.HierarchyName << "::" << node.getId() << ":\n"
- " return " << info.MethodPrefix << node.getClassName() << "(";
- if (!info.IsReader)
- Out << "static_cast<const " << node.getClassName()
- << " *>(node)";
- Out << ");\n";
- });
- Out << " }\n"
- " llvm_unreachable(\"bad kind\");\n"
- " }\n\n";
- // Emit node-specific methods for all the concrete nodes.
- visitASTNodeHierarchy<NodeClass>(Records,
- [&](NodeClass node, NodeClass base) {
- if (node.isAbstract()) return;
- emitNodeReaderWriterMethod(node, info);
- });
- // Finish the class.
- Out << "};\n\n";
- }
- /// Emit a reader method for the given concrete AST node class.
- template <class NodeClass>
- void ASTPropsEmitter::emitNodeReaderWriterMethod(NodeClass node,
- const ReaderWriterInfo &info) {
- // Declare and start the method.
- Out << " " << info.ResultType << " "
- << info.MethodPrefix << node.getClassName() << "(";
- if (!info.IsReader)
- Out << "const " << node.getClassName() << " *node";
- Out << ") {\n";
- 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())
- PrintFatalError(node.getLoc(),
- "no information about how to deserialize \""
- + node.getName() + "\"");
- auto &nodeInfo = it->second;
- StringRef creationCode;
- if (info.IsReader) {
- // We should have a creation rule.
- if (!nodeInfo.Creator)
- PrintFatalError(node.getLoc(),
- "no " CreationRuleClassName " for \""
- + node.getName() + "\"");
- creationCode = nodeInfo.Creator.getCreationCode();
- }
- // Emit the ReadHelper code, if present.
- if (!info.IsReader && nodeInfo.ReadHelper) {
- Out << " " << nodeInfo.ReadHelper.getHelperCode() << "\n";
- }
- // Emit code to read all the properties.
- visitAllProperties(node, nodeInfo, [&](Property prop) {
- // Verify that the creation code refers to this property.
- if (info.IsReader && !creationCode.contains(prop.getName()))
- PrintFatalError(nodeInfo.Creator.getLoc(),
- "creation code for " + node.getName()
- + " doesn't refer to property \""
- + prop.getName() + "\"");
- // Emit code to read or write this property.
- if (info.IsReader)
- emitReadOfProperty(info.HelperVariable, prop);
- else
- emitWriteOfProperty(info.HelperVariable, prop);
- });
- // Emit the final creation code.
- if (info.IsReader)
- Out << " " << creationCode << "\n";
- }
- static void emitBasicReaderWriterMethodSuffix(raw_ostream &out,
- PropertyType type,
- bool isForRead) {
- if (!type.isGenericSpecialization()) {
- out << type.getAbstractTypeName();
- } else if (auto eltType = type.getArrayElementType()) {
- out << "Array";
- // We only include an explicit template argument for reads so that
- // we don't cause spurious const mismatches.
- if (isForRead) {
- out << "<";
- eltType.emitCXXValueTypeName(isForRead, out);
- out << ">";
- }
- } else if (auto valueType = type.getOptionalElementType()) {
- out << "Optional";
- // We only include an explicit template argument for reads so that
- // we don't cause spurious const mismatches.
- if (isForRead) {
- out << "<";
- valueType.emitCXXValueTypeName(isForRead, out);
- out << ">";
- }
- } else {
- PrintFatalError(type.getLoc(), "unexpected generic property type");
- }
- }
- /// Emit code to read the given property in a node-reader method.
- void ASTPropsEmitter::emitReadOfProperty(StringRef readerName,
- Property property) {
- emitReadOfProperty(readerName, property.getName(), property.getType(),
- property.getCondition());
- }
- void ASTPropsEmitter::emitReadOfProperty(StringRef readerName,
- StringRef name,
- PropertyType type,
- StringRef condition) {
- // Declare all the necessary buffers.
- auto bufferTypes = type.getBufferElementTypes();
- for (size_t i = 0, e = bufferTypes.size(); i != e; ++i) {
- Out << " llvm::SmallVector<";
- PropertyType(bufferTypes[i]).emitCXXValueTypeName(/*for read*/ true, Out);
- Out << ", 8> " << name << "_buffer_" << i << ";\n";
- }
- // T prop = R.find("prop").read##ValueType(buffers...);
- // We intentionally ignore shouldPassByReference here: we're going to
- // get a pr-value back from read(), and we should be able to forward
- // that in the creation rule.
- Out << " ";
- if (!condition.empty())
- Out << "std::optional<";
- type.emitCXXValueTypeName(true, Out);
- if (!condition.empty()) Out << ">";
- Out << " " << name;
- if (condition.empty()) {
- Out << " = ";
- } else {
- Out << ";\n"
- " if (" << condition << ") {\n"
- " " << name << ".emplace(";
- }
- Out << readerName << ".find(\"" << name << "\")."
- << (type.isGenericSpecialization() ? "template " : "") << "read";
- emitBasicReaderWriterMethodSuffix(Out, type, /*for read*/ true);
- Out << "(";
- for (size_t i = 0, e = bufferTypes.size(); i != e; ++i) {
- Out << (i > 0 ? ", " : "") << name << "_buffer_" << i;
- }
- Out << ")";
- if (condition.empty()) {
- Out << ";\n";
- } else {
- Out << ");\n"
- " }\n";
- }
- }
- /// Emit code to write the given property in a node-writer method.
- void ASTPropsEmitter::emitWriteOfProperty(StringRef writerName,
- Property property) {
- emitWriteOfProperty(writerName, property.getName(), property.getType(),
- property.getReadCode(), property.getCondition());
- }
- void ASTPropsEmitter::emitWriteOfProperty(StringRef writerName,
- StringRef name,
- PropertyType type,
- StringRef readCode,
- StringRef condition) {
- if (!condition.empty()) {
- Out << " if (" << condition << ") {\n";
- }
- // Focus down to the property:
- // T prop = <READ>;
- // W.find("prop").write##ValueType(prop);
- Out << " ";
- type.emitCXXValueTypeName(false, Out);
- Out << " " << name << " = (" << readCode << ");\n"
- " " << writerName << ".find(\"" << name << "\").write";
- emitBasicReaderWriterMethodSuffix(Out, type, /*for read*/ false);
- Out << "(" << name << ");\n";
- if (!condition.empty()) {
- Out << " }\n";
- }
- }
- /// Emit an .inc file that defines the AbstractFooReader class
- /// for the given AST class hierarchy.
- template <class NodeClass>
- static void emitASTReader(RecordKeeper &records, raw_ostream &out,
- StringRef description) {
- emitSourceFileHeader(description, out);
- ASTPropsEmitter(records, out).emitNodeReaderClass<NodeClass>();
- }
- void clang::EmitClangTypeReader(RecordKeeper &records, raw_ostream &out) {
- emitASTReader<TypeNode>(records, out, "A CRTP reader for Clang Type nodes");
- }
- /// Emit an .inc file that defines the AbstractFooWriter class
- /// for the given AST class hierarchy.
- template <class NodeClass>
- static void emitASTWriter(RecordKeeper &records, raw_ostream &out,
- StringRef description) {
- emitSourceFileHeader(description, out);
- ASTPropsEmitter(records, out).emitNodeWriterClass<NodeClass>();
- }
- void clang::EmitClangTypeWriter(RecordKeeper &records, raw_ostream &out) {
- emitASTWriter<TypeNode>(records, out, "A CRTP writer for Clang Type nodes");
- }
- /****************************************************************************/
- /*************************** BASIC READER/WRITERS ***************************/
- /****************************************************************************/
- void
- ASTPropsEmitter::emitDispatcherTemplate(const ReaderWriterInfo &info) {
- // Declare the {Read,Write}Dispatcher template.
- StringRef dispatcherPrefix = (info.IsReader ? "Read" : "Write");
- Out << "template <class ValueType>\n"
- "struct " << dispatcherPrefix << "Dispatcher;\n";
- // Declare a specific specialization of the dispatcher template.
- auto declareSpecialization =
- [&](StringRef specializationParameters,
- const Twine &cxxTypeName,
- StringRef methodSuffix) {
- StringRef var = info.HelperVariable;
- Out << "template " << specializationParameters << "\n"
- "struct " << dispatcherPrefix << "Dispatcher<"
- << cxxTypeName << "> {\n";
- Out << " template <class Basic" << info.ClassSuffix << ", class... Args>\n"
- " static " << (info.IsReader ? cxxTypeName : "void") << " "
- << info.MethodPrefix
- << "(Basic" << info.ClassSuffix << " &" << var
- << ", Args &&... args) {\n"
- " return " << var << "."
- << info.MethodPrefix << methodSuffix
- << "(std::forward<Args>(args)...);\n"
- " }\n"
- "};\n";
- };
- // Declare explicit specializations for each of the concrete types.
- for (PropertyType type : AllPropertyTypes) {
- declareSpecialization("<>",
- type.getCXXTypeName(),
- type.getAbstractTypeName());
- // Also declare a specialization for the const type when appropriate.
- if (!info.IsReader && type.isConstWhenWriting()) {
- declareSpecialization("<>",
- "const " + type.getCXXTypeName(),
- type.getAbstractTypeName());
- }
- }
- // Declare partial specializations for ArrayRef and Optional.
- declareSpecialization("<class T>",
- "llvm::ArrayRef<T>",
- "Array");
- declareSpecialization("<class T>", "std::optional<T>", "Optional");
- Out << "\n";
- }
- void
- ASTPropsEmitter::emitPackUnpackOptionalTemplate(const ReaderWriterInfo &info) {
- StringRef classPrefix = (info.IsReader ? "Unpack" : "Pack");
- StringRef methodName = (info.IsReader ? "unpack" : "pack");
- // Declare the {Pack,Unpack}OptionalValue template.
- Out << "template <class ValueType>\n"
- "struct " << classPrefix << "OptionalValue;\n";
- auto declareSpecialization = [&](const Twine &typeName, StringRef code) {
- Out << "template <>\n"
- "struct "
- << classPrefix << "OptionalValue<" << typeName
- << "> {\n"
- " static "
- << (info.IsReader ? "std::optional<" : "") << typeName
- << (info.IsReader ? "> " : " ") << methodName << "("
- << (info.IsReader ? "" : "std::optional<") << typeName
- << (info.IsReader ? "" : ">")
- << " value) {\n"
- " return "
- << code
- << ";\n"
- " }\n"
- "};\n";
- };
- for (PropertyType type : AllPropertyTypes) {
- StringRef code = (info.IsReader ? type.getUnpackOptionalCode()
- : type.getPackOptionalCode());
- if (code.empty()) continue;
- StringRef typeName = type.getCXXTypeName();
- declareSpecialization(typeName, code);
- if (type.isConstWhenWriting() && !info.IsReader)
- declareSpecialization("const " + typeName, code);
- }
- Out << "\n";
- }
- void
- ASTPropsEmitter::emitBasicReaderWriterTemplate(const ReaderWriterInfo &info) {
- // Emit the Basic{Reader,Writer}Base template.
- Out << "template <class Impl>\n"
- "class Basic" << info.ClassSuffix << "Base {\n";
- Out << " ASTContext &C;\n";
- Out << "protected:\n"
- " Basic"
- << info.ClassSuffix << "Base" << ("(ASTContext &ctx) : C(ctx)")
- << " {}\n"
- "public:\n";
- Out << " ASTContext &getASTContext() { return C; }\n";
- Out << " Impl &asImpl() { return static_cast<Impl&>(*this); }\n";
- auto enterReaderWriterMethod = [&](StringRef cxxTypeName,
- StringRef abstractTypeName,
- bool shouldPassByReference,
- bool constWhenWriting,
- StringRef paramName) {
- Out << " " << (info.IsReader ? cxxTypeName : "void")
- << " " << info.MethodPrefix << abstractTypeName << "(";
- if (!info.IsReader)
- Out << (shouldPassByReference || constWhenWriting ? "const " : "")
- << cxxTypeName
- << (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) {
- auto enterMethod = [&](StringRef paramName) {
- enterReaderWriterMethod(type.getCXXTypeName(),
- type.getAbstractTypeName(),
- 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 asImpl().template readEnum<"
- << type.getCXXTypeName() << ">();\n";
- else
- Out << " asImpl().writeEnum(value);\n";
- exitMethod();
- } else if (PropertyType superclass = type.getSuperclassType()) {
- enterMethod("value");
- if (info.IsReader)
- Out << " return cast_or_null<" << type.getSubclassClassName()
- << ">(asImpl().read"
- << superclass.getAbstractTypeName()
- << "());\n";
- else
- Out << " asImpl().write" << superclass.getAbstractTypeName()
- << "(value);\n";
- exitMethod();
- } else {
- // The other types can't be handled as trivially.
- }
- }
- Out << "};\n\n";
- }
- 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 {
- // Write the property. Note that this will implicitly read the
- // kind into a local variable with the right name.
- emitWriteOfProperty(subvar, kindProperty, kindType,
- kindRule.getReadCode());
- }
- // 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);
- }
- /// Emit an .inc file that defines some helper classes for reading
- /// basic values.
- void clang::EmitClangBasicReader(RecordKeeper &records, raw_ostream &out) {
- emitSourceFileHeader("Helper classes for BasicReaders", out);
- // Use any property, we won't be using those properties.
- auto info = ReaderWriterInfo::forReader<TypeNode>();
- ASTPropsEmitter(records, out).emitBasicReaderWriterFile(info);
- }
- /// Emit an .inc file that defines some helper classes for writing
- /// basic values.
- void clang::EmitClangBasicWriter(RecordKeeper &records, raw_ostream &out) {
- emitSourceFileHeader("Helper classes for BasicWriters", out);
- // Use any property, we won't be using those properties.
- auto info = ReaderWriterInfo::forWriter<TypeNode>();
- ASTPropsEmitter(records, out).emitBasicReaderWriterFile(info);
- }
|