1480093f4SDimitry Andric //=== ClangASTPropsEmitter.cpp - Generate Clang AST properties --*- C++ -*-===//
2480093f4SDimitry Andric //
3480093f4SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4480093f4SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5480093f4SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6480093f4SDimitry Andric //
7480093f4SDimitry Andric //===----------------------------------------------------------------------===//
8480093f4SDimitry Andric //
9480093f4SDimitry Andric // This tablegen backend emits code for working with Clang AST properties.
10480093f4SDimitry Andric //
11480093f4SDimitry Andric //===----------------------------------------------------------------------===//
12480093f4SDimitry Andric
13480093f4SDimitry Andric #include "ASTTableGen.h"
14480093f4SDimitry Andric #include "TableGenBackends.h"
15480093f4SDimitry Andric
16480093f4SDimitry Andric #include "llvm/ADT/STLExtras.h"
17480093f4SDimitry Andric #include "llvm/ADT/Twine.h"
18480093f4SDimitry Andric #include "llvm/TableGen/Error.h"
19480093f4SDimitry Andric #include "llvm/TableGen/Record.h"
20480093f4SDimitry Andric #include "llvm/TableGen/TableGenBackend.h"
21480093f4SDimitry Andric #include <cctype>
22480093f4SDimitry Andric #include <map>
23bdd1243dSDimitry Andric #include <optional>
24480093f4SDimitry Andric #include <set>
25480093f4SDimitry Andric #include <string>
26480093f4SDimitry Andric using namespace llvm;
27480093f4SDimitry Andric using namespace clang;
28480093f4SDimitry Andric using namespace clang::tblgen;
29480093f4SDimitry Andric
getReaderResultType(TypeNode _)30480093f4SDimitry Andric static StringRef getReaderResultType(TypeNode _) { return "QualType"; }
31480093f4SDimitry Andric
32480093f4SDimitry Andric namespace {
33480093f4SDimitry Andric
34480093f4SDimitry Andric struct ReaderWriterInfo {
35480093f4SDimitry Andric bool IsReader;
36480093f4SDimitry Andric
37480093f4SDimitry Andric /// The name of the node hierarchy. Not actually sensitive to IsReader,
38480093f4SDimitry Andric /// but useful to cache here anyway.
39480093f4SDimitry Andric StringRef HierarchyName;
40480093f4SDimitry Andric
41480093f4SDimitry Andric /// The suffix on classes: Reader/Writer
42480093f4SDimitry Andric StringRef ClassSuffix;
43480093f4SDimitry Andric
44480093f4SDimitry Andric /// The base name of methods: read/write
45480093f4SDimitry Andric StringRef MethodPrefix;
46480093f4SDimitry Andric
47480093f4SDimitry Andric /// The name of the property helper member: R/W
48480093f4SDimitry Andric StringRef HelperVariable;
49480093f4SDimitry Andric
50480093f4SDimitry Andric /// The result type of methods on the class.
51480093f4SDimitry Andric StringRef ResultType;
52480093f4SDimitry Andric
53480093f4SDimitry Andric template <class NodeClass>
forReader__anon8e7483cb0111::ReaderWriterInfo54480093f4SDimitry Andric static ReaderWriterInfo forReader() {
55480093f4SDimitry Andric return ReaderWriterInfo{
56480093f4SDimitry Andric true,
57480093f4SDimitry Andric NodeClass::getASTHierarchyName(),
58480093f4SDimitry Andric "Reader",
59480093f4SDimitry Andric "read",
60480093f4SDimitry Andric "R",
61480093f4SDimitry Andric getReaderResultType(NodeClass())
62480093f4SDimitry Andric };
63480093f4SDimitry Andric }
64480093f4SDimitry Andric
65480093f4SDimitry Andric template <class NodeClass>
forWriter__anon8e7483cb0111::ReaderWriterInfo66480093f4SDimitry Andric static ReaderWriterInfo forWriter() {
67480093f4SDimitry Andric return ReaderWriterInfo{
68480093f4SDimitry Andric false,
69480093f4SDimitry Andric NodeClass::getASTHierarchyName(),
70480093f4SDimitry Andric "Writer",
71480093f4SDimitry Andric "write",
72480093f4SDimitry Andric "W",
73480093f4SDimitry Andric "void"
74480093f4SDimitry Andric };
75480093f4SDimitry Andric }
76480093f4SDimitry Andric };
77480093f4SDimitry Andric
78480093f4SDimitry Andric struct NodeInfo {
79480093f4SDimitry Andric std::vector<Property> Properties;
80480093f4SDimitry Andric CreationRule Creator = nullptr;
81480093f4SDimitry Andric OverrideRule Override = nullptr;
82480093f4SDimitry Andric ReadHelperRule ReadHelper = nullptr;
83480093f4SDimitry Andric };
84480093f4SDimitry Andric
85480093f4SDimitry Andric struct CasedTypeInfo {
86480093f4SDimitry Andric TypeKindRule KindRule;
87480093f4SDimitry Andric std::vector<TypeCase> Cases;
88480093f4SDimitry Andric };
89480093f4SDimitry Andric
90480093f4SDimitry Andric class ASTPropsEmitter {
91480093f4SDimitry Andric raw_ostream &Out;
92480093f4SDimitry Andric RecordKeeper &Records;
93480093f4SDimitry Andric std::map<HasProperties, NodeInfo> NodeInfos;
94480093f4SDimitry Andric std::vector<PropertyType> AllPropertyTypes;
95480093f4SDimitry Andric std::map<PropertyType, CasedTypeInfo> CasedTypeInfos;
96480093f4SDimitry Andric
97480093f4SDimitry Andric public:
ASTPropsEmitter(RecordKeeper & records,raw_ostream & out)98480093f4SDimitry Andric ASTPropsEmitter(RecordKeeper &records, raw_ostream &out)
99480093f4SDimitry Andric : Out(out), Records(records) {
100480093f4SDimitry Andric
101480093f4SDimitry Andric // Find all the properties.
102480093f4SDimitry Andric for (Property property :
103480093f4SDimitry Andric records.getAllDerivedDefinitions(PropertyClassName)) {
104480093f4SDimitry Andric HasProperties node = property.getClass();
105480093f4SDimitry Andric NodeInfos[node].Properties.push_back(property);
106480093f4SDimitry Andric }
107480093f4SDimitry Andric
108480093f4SDimitry Andric // Find all the creation rules.
109480093f4SDimitry Andric for (CreationRule creationRule :
110480093f4SDimitry Andric records.getAllDerivedDefinitions(CreationRuleClassName)) {
111480093f4SDimitry Andric HasProperties node = creationRule.getClass();
112480093f4SDimitry Andric
113480093f4SDimitry Andric auto &info = NodeInfos[node];
114480093f4SDimitry Andric if (info.Creator) {
115480093f4SDimitry Andric PrintFatalError(creationRule.getLoc(),
116480093f4SDimitry Andric "multiple creator rules for \"" + node.getName()
117480093f4SDimitry Andric + "\"");
118480093f4SDimitry Andric }
119480093f4SDimitry Andric info.Creator = creationRule;
120480093f4SDimitry Andric }
121480093f4SDimitry Andric
122480093f4SDimitry Andric // Find all the override rules.
123480093f4SDimitry Andric for (OverrideRule overrideRule :
124480093f4SDimitry Andric records.getAllDerivedDefinitions(OverrideRuleClassName)) {
125480093f4SDimitry Andric HasProperties node = overrideRule.getClass();
126480093f4SDimitry Andric
127480093f4SDimitry Andric auto &info = NodeInfos[node];
128480093f4SDimitry Andric if (info.Override) {
129480093f4SDimitry Andric PrintFatalError(overrideRule.getLoc(),
130480093f4SDimitry Andric "multiple override rules for \"" + node.getName()
131480093f4SDimitry Andric + "\"");
132480093f4SDimitry Andric }
133480093f4SDimitry Andric info.Override = overrideRule;
134480093f4SDimitry Andric }
135480093f4SDimitry Andric
136480093f4SDimitry Andric // Find all the write helper rules.
137480093f4SDimitry Andric for (ReadHelperRule helperRule :
138480093f4SDimitry Andric records.getAllDerivedDefinitions(ReadHelperRuleClassName)) {
139480093f4SDimitry Andric HasProperties node = helperRule.getClass();
140480093f4SDimitry Andric
141480093f4SDimitry Andric auto &info = NodeInfos[node];
142480093f4SDimitry Andric if (info.ReadHelper) {
143480093f4SDimitry Andric PrintFatalError(helperRule.getLoc(),
144480093f4SDimitry Andric "multiple write helper rules for \"" + node.getName()
145480093f4SDimitry Andric + "\"");
146480093f4SDimitry Andric }
147480093f4SDimitry Andric info.ReadHelper = helperRule;
148480093f4SDimitry Andric }
149480093f4SDimitry Andric
150480093f4SDimitry Andric // Find all the concrete property types.
151480093f4SDimitry Andric for (PropertyType type :
152480093f4SDimitry Andric records.getAllDerivedDefinitions(PropertyTypeClassName)) {
153480093f4SDimitry Andric // Ignore generic specializations; they're generally not useful when
154480093f4SDimitry Andric // emitting basic emitters etc.
155480093f4SDimitry Andric if (type.isGenericSpecialization()) continue;
156480093f4SDimitry Andric
157480093f4SDimitry Andric AllPropertyTypes.push_back(type);
158480093f4SDimitry Andric }
159480093f4SDimitry Andric
160480093f4SDimitry Andric // Find all the type kind rules.
161480093f4SDimitry Andric for (TypeKindRule kindRule :
162480093f4SDimitry Andric records.getAllDerivedDefinitions(TypeKindClassName)) {
163480093f4SDimitry Andric PropertyType type = kindRule.getParentType();
164480093f4SDimitry Andric auto &info = CasedTypeInfos[type];
165480093f4SDimitry Andric if (info.KindRule) {
166480093f4SDimitry Andric PrintFatalError(kindRule.getLoc(),
167480093f4SDimitry Andric "multiple kind rules for \""
168480093f4SDimitry Andric + type.getCXXTypeName() + "\"");
169480093f4SDimitry Andric }
170480093f4SDimitry Andric info.KindRule = kindRule;
171480093f4SDimitry Andric }
172480093f4SDimitry Andric
173480093f4SDimitry Andric // Find all the type cases.
174480093f4SDimitry Andric for (TypeCase typeCase :
175480093f4SDimitry Andric records.getAllDerivedDefinitions(TypeCaseClassName)) {
176480093f4SDimitry Andric CasedTypeInfos[typeCase.getParentType()].Cases.push_back(typeCase);
177480093f4SDimitry Andric }
178480093f4SDimitry Andric
179480093f4SDimitry Andric Validator(*this).validate();
180480093f4SDimitry Andric }
181480093f4SDimitry Andric
visitAllProperties(HasProperties derived,const NodeInfo & derivedInfo,function_ref<void (Property)> visit)182480093f4SDimitry Andric void visitAllProperties(HasProperties derived, const NodeInfo &derivedInfo,
183480093f4SDimitry Andric function_ref<void (Property)> visit) {
184480093f4SDimitry Andric std::set<StringRef> ignoredProperties;
185480093f4SDimitry Andric
186480093f4SDimitry Andric auto overrideRule = derivedInfo.Override;
187480093f4SDimitry Andric if (overrideRule) {
188480093f4SDimitry Andric auto list = overrideRule.getIgnoredProperties();
189480093f4SDimitry Andric ignoredProperties.insert(list.begin(), list.end());
190480093f4SDimitry Andric }
191480093f4SDimitry Andric
192480093f4SDimitry Andric // TODO: we should sort the properties in various ways
193480093f4SDimitry Andric // - put arrays at the end to enable abbreviations
194480093f4SDimitry Andric // - put conditional properties after properties used in the condition
195480093f4SDimitry Andric
196480093f4SDimitry Andric visitAllNodesWithInfo(derived, derivedInfo,
197480093f4SDimitry Andric [&](HasProperties node, const NodeInfo &info) {
198480093f4SDimitry Andric for (Property prop : info.Properties) {
199480093f4SDimitry Andric if (ignoredProperties.count(prop.getName()))
200480093f4SDimitry Andric continue;
201480093f4SDimitry Andric
202480093f4SDimitry Andric visit(prop);
203480093f4SDimitry Andric }
204480093f4SDimitry Andric });
205480093f4SDimitry Andric }
206480093f4SDimitry Andric
visitAllNodesWithInfo(HasProperties derivedNode,const NodeInfo & derivedNodeInfo,llvm::function_ref<void (HasProperties node,const NodeInfo & info)> visit)207480093f4SDimitry Andric void visitAllNodesWithInfo(HasProperties derivedNode,
208480093f4SDimitry Andric const NodeInfo &derivedNodeInfo,
209480093f4SDimitry Andric llvm::function_ref<void (HasProperties node,
210480093f4SDimitry Andric const NodeInfo &info)>
211480093f4SDimitry Andric visit) {
212480093f4SDimitry Andric visit(derivedNode, derivedNodeInfo);
213480093f4SDimitry Andric
214480093f4SDimitry Andric // Also walk the bases if appropriate.
215480093f4SDimitry Andric if (ASTNode base = derivedNode.getAs<ASTNode>()) {
216480093f4SDimitry Andric for (base = base.getBase(); base; base = base.getBase()) {
217480093f4SDimitry Andric auto it = NodeInfos.find(base);
218480093f4SDimitry Andric
219480093f4SDimitry Andric // Ignore intermediate nodes that don't add interesting properties.
220480093f4SDimitry Andric if (it == NodeInfos.end()) continue;
221480093f4SDimitry Andric auto &baseInfo = it->second;
222480093f4SDimitry Andric
223480093f4SDimitry Andric visit(base, baseInfo);
224480093f4SDimitry Andric }
225480093f4SDimitry Andric }
226480093f4SDimitry Andric }
227480093f4SDimitry Andric
228480093f4SDimitry Andric template <class NodeClass>
emitNodeReaderClass()229480093f4SDimitry Andric void emitNodeReaderClass() {
230480093f4SDimitry Andric auto info = ReaderWriterInfo::forReader<NodeClass>();
231480093f4SDimitry Andric emitNodeReaderWriterClass<NodeClass>(info);
232480093f4SDimitry Andric }
233480093f4SDimitry Andric
234480093f4SDimitry Andric template <class NodeClass>
emitNodeWriterClass()235480093f4SDimitry Andric void emitNodeWriterClass() {
236480093f4SDimitry Andric auto info = ReaderWriterInfo::forWriter<NodeClass>();
237480093f4SDimitry Andric emitNodeReaderWriterClass<NodeClass>(info);
238480093f4SDimitry Andric }
239480093f4SDimitry Andric
240480093f4SDimitry Andric template <class NodeClass>
241480093f4SDimitry Andric void emitNodeReaderWriterClass(const ReaderWriterInfo &info);
242480093f4SDimitry Andric
243480093f4SDimitry Andric template <class NodeClass>
244480093f4SDimitry Andric void emitNodeReaderWriterMethod(NodeClass node,
245480093f4SDimitry Andric const ReaderWriterInfo &info);
246480093f4SDimitry Andric
247480093f4SDimitry Andric void emitPropertiedReaderWriterBody(HasProperties node,
248480093f4SDimitry Andric const ReaderWriterInfo &info);
249480093f4SDimitry Andric
250480093f4SDimitry Andric void emitReadOfProperty(StringRef readerName, Property property);
251480093f4SDimitry Andric void emitReadOfProperty(StringRef readerName, StringRef name,
252480093f4SDimitry Andric PropertyType type, StringRef condition = "");
253480093f4SDimitry Andric
254480093f4SDimitry Andric void emitWriteOfProperty(StringRef writerName, Property property);
255480093f4SDimitry Andric void emitWriteOfProperty(StringRef writerName, StringRef name,
256480093f4SDimitry Andric PropertyType type, StringRef readCode,
257480093f4SDimitry Andric StringRef condition = "");
258480093f4SDimitry Andric
259480093f4SDimitry Andric void emitBasicReaderWriterFile(const ReaderWriterInfo &info);
260480093f4SDimitry Andric void emitDispatcherTemplate(const ReaderWriterInfo &info);
261480093f4SDimitry Andric void emitPackUnpackOptionalTemplate(const ReaderWriterInfo &info);
262480093f4SDimitry Andric void emitBasicReaderWriterTemplate(const ReaderWriterInfo &info);
263480093f4SDimitry Andric
264480093f4SDimitry Andric void emitCasedReaderWriterMethodBody(PropertyType type,
265480093f4SDimitry Andric const CasedTypeInfo &typeCases,
266480093f4SDimitry Andric const ReaderWriterInfo &info);
267480093f4SDimitry Andric
268480093f4SDimitry Andric private:
269480093f4SDimitry Andric class Validator {
270480093f4SDimitry Andric ASTPropsEmitter &Emitter;
271480093f4SDimitry Andric std::set<HasProperties> ValidatedNodes;
272480093f4SDimitry Andric
273480093f4SDimitry Andric public:
Validator(ASTPropsEmitter & emitter)274480093f4SDimitry Andric Validator(ASTPropsEmitter &emitter) : Emitter(emitter) {}
275480093f4SDimitry Andric void validate();
276480093f4SDimitry Andric
277480093f4SDimitry Andric private:
278480093f4SDimitry Andric void validateNode(HasProperties node, const NodeInfo &nodeInfo);
279480093f4SDimitry Andric void validateType(PropertyType type, WrappedRecord context);
280480093f4SDimitry Andric };
281480093f4SDimitry Andric };
282480093f4SDimitry Andric
283480093f4SDimitry Andric } // end anonymous namespace
284480093f4SDimitry Andric
validate()285480093f4SDimitry Andric void ASTPropsEmitter::Validator::validate() {
286480093f4SDimitry Andric for (auto &entry : Emitter.NodeInfos) {
287480093f4SDimitry Andric validateNode(entry.first, entry.second);
288480093f4SDimitry Andric }
289480093f4SDimitry Andric
290480093f4SDimitry Andric if (ErrorsPrinted > 0) {
291480093f4SDimitry Andric PrintFatalError("property validation failed");
292480093f4SDimitry Andric }
293480093f4SDimitry Andric }
294480093f4SDimitry Andric
validateNode(HasProperties derivedNode,const NodeInfo & derivedNodeInfo)295480093f4SDimitry Andric void ASTPropsEmitter::Validator::validateNode(HasProperties derivedNode,
296480093f4SDimitry Andric const NodeInfo &derivedNodeInfo) {
297480093f4SDimitry Andric if (!ValidatedNodes.insert(derivedNode).second) return;
298480093f4SDimitry Andric
299480093f4SDimitry Andric // A map from property name to property.
300480093f4SDimitry Andric std::map<StringRef, Property> allProperties;
301480093f4SDimitry Andric
302480093f4SDimitry Andric Emitter.visitAllNodesWithInfo(derivedNode, derivedNodeInfo,
303480093f4SDimitry Andric [&](HasProperties node,
304480093f4SDimitry Andric const NodeInfo &nodeInfo) {
305480093f4SDimitry Andric for (Property property : nodeInfo.Properties) {
306480093f4SDimitry Andric validateType(property.getType(), property);
307480093f4SDimitry Andric
308480093f4SDimitry Andric auto result = allProperties.insert(
309480093f4SDimitry Andric std::make_pair(property.getName(), property));
310480093f4SDimitry Andric
311480093f4SDimitry Andric // Diagnose non-unique properties.
312480093f4SDimitry Andric if (!result.second) {
313480093f4SDimitry Andric // The existing property is more likely to be associated with a
314480093f4SDimitry Andric // derived node, so use it as the error.
315480093f4SDimitry Andric Property existingProperty = result.first->second;
316480093f4SDimitry Andric PrintError(existingProperty.getLoc(),
317480093f4SDimitry Andric "multiple properties named \"" + property.getName()
318480093f4SDimitry Andric + "\" in hierarchy of " + derivedNode.getName());
319480093f4SDimitry Andric PrintNote(property.getLoc(), "existing property");
320480093f4SDimitry Andric }
321480093f4SDimitry Andric }
322480093f4SDimitry Andric });
323480093f4SDimitry Andric }
324480093f4SDimitry Andric
validateType(PropertyType type,WrappedRecord context)325480093f4SDimitry Andric void ASTPropsEmitter::Validator::validateType(PropertyType type,
326480093f4SDimitry Andric WrappedRecord context) {
327480093f4SDimitry Andric if (!type.isGenericSpecialization()) {
328480093f4SDimitry Andric if (type.getCXXTypeName() == "") {
329480093f4SDimitry Andric PrintError(type.getLoc(),
330480093f4SDimitry Andric "type is not generic but has no C++ type name");
331480093f4SDimitry Andric if (context) PrintNote(context.getLoc(), "type used here");
332480093f4SDimitry Andric }
333480093f4SDimitry Andric } else if (auto eltType = type.getArrayElementType()) {
334480093f4SDimitry Andric validateType(eltType, context);
335480093f4SDimitry Andric } else if (auto valueType = type.getOptionalElementType()) {
336480093f4SDimitry Andric validateType(valueType, context);
337480093f4SDimitry Andric
338480093f4SDimitry Andric if (valueType.getPackOptionalCode().empty()) {
339480093f4SDimitry Andric PrintError(valueType.getLoc(),
340480093f4SDimitry Andric "type doesn't provide optional-packing code");
341480093f4SDimitry Andric if (context) PrintNote(context.getLoc(), "type used here");
342480093f4SDimitry Andric } else if (valueType.getUnpackOptionalCode().empty()) {
343480093f4SDimitry Andric PrintError(valueType.getLoc(),
344480093f4SDimitry Andric "type doesn't provide optional-unpacking code");
345480093f4SDimitry Andric if (context) PrintNote(context.getLoc(), "type used here");
346480093f4SDimitry Andric }
347480093f4SDimitry Andric } else {
348480093f4SDimitry Andric PrintError(type.getLoc(), "unknown generic property type");
349480093f4SDimitry Andric if (context) PrintNote(context.getLoc(), "type used here");
350480093f4SDimitry Andric }
351480093f4SDimitry Andric }
352480093f4SDimitry Andric
353480093f4SDimitry Andric /****************************************************************************/
354480093f4SDimitry Andric /**************************** AST READER/WRITERS ****************************/
355480093f4SDimitry Andric /****************************************************************************/
356480093f4SDimitry Andric
357480093f4SDimitry Andric template <class NodeClass>
emitNodeReaderWriterClass(const ReaderWriterInfo & info)358480093f4SDimitry Andric void ASTPropsEmitter::emitNodeReaderWriterClass(const ReaderWriterInfo &info) {
359480093f4SDimitry Andric StringRef suffix = info.ClassSuffix;
360480093f4SDimitry Andric StringRef var = info.HelperVariable;
361480093f4SDimitry Andric
362480093f4SDimitry Andric // Enter the class declaration.
363480093f4SDimitry Andric Out << "template <class Property" << suffix << ">\n"
364480093f4SDimitry Andric "class Abstract" << info.HierarchyName << suffix << " {\n"
365480093f4SDimitry Andric "public:\n"
366480093f4SDimitry Andric " Property" << suffix << " &" << var << ";\n\n";
367480093f4SDimitry Andric
368480093f4SDimitry Andric // Emit the constructor.
369480093f4SDimitry Andric Out << " Abstract" << info.HierarchyName << suffix
370480093f4SDimitry Andric << "(Property" << suffix << " &" << var << ") : "
371480093f4SDimitry Andric << var << "(" << var << ") {}\n\n";
372480093f4SDimitry Andric
373480093f4SDimitry Andric // Emit a method that dispatches on a kind to the appropriate node-specific
374480093f4SDimitry Andric // method.
375480093f4SDimitry Andric Out << " " << info.ResultType << " " << info.MethodPrefix << "(";
376480093f4SDimitry Andric if (info.IsReader)
377480093f4SDimitry Andric Out << NodeClass::getASTIdTypeName() << " kind";
378480093f4SDimitry Andric else
379480093f4SDimitry Andric Out << "const " << info.HierarchyName << " *node";
380480093f4SDimitry Andric Out << ") {\n"
381480093f4SDimitry Andric " switch (";
382480093f4SDimitry Andric if (info.IsReader)
383480093f4SDimitry Andric Out << "kind";
384480093f4SDimitry Andric else
385480093f4SDimitry Andric Out << "node->" << NodeClass::getASTIdAccessorName() << "()";
386480093f4SDimitry Andric Out << ") {\n";
387480093f4SDimitry Andric visitASTNodeHierarchy<NodeClass>(Records, [&](NodeClass node, NodeClass _) {
388480093f4SDimitry Andric if (node.isAbstract()) return;
389480093f4SDimitry Andric Out << " case " << info.HierarchyName << "::" << node.getId() << ":\n"
390480093f4SDimitry Andric " return " << info.MethodPrefix << node.getClassName() << "(";
391480093f4SDimitry Andric if (!info.IsReader)
392480093f4SDimitry Andric Out << "static_cast<const " << node.getClassName()
393480093f4SDimitry Andric << " *>(node)";
394480093f4SDimitry Andric Out << ");\n";
395480093f4SDimitry Andric });
396480093f4SDimitry Andric Out << " }\n"
397480093f4SDimitry Andric " llvm_unreachable(\"bad kind\");\n"
398480093f4SDimitry Andric " }\n\n";
399480093f4SDimitry Andric
400480093f4SDimitry Andric // Emit node-specific methods for all the concrete nodes.
401480093f4SDimitry Andric visitASTNodeHierarchy<NodeClass>(Records,
402480093f4SDimitry Andric [&](NodeClass node, NodeClass base) {
403480093f4SDimitry Andric if (node.isAbstract()) return;
404480093f4SDimitry Andric emitNodeReaderWriterMethod(node, info);
405480093f4SDimitry Andric });
406480093f4SDimitry Andric
407480093f4SDimitry Andric // Finish the class.
408480093f4SDimitry Andric Out << "};\n\n";
409480093f4SDimitry Andric }
410480093f4SDimitry Andric
411480093f4SDimitry Andric /// Emit a reader method for the given concrete AST node class.
412480093f4SDimitry Andric template <class NodeClass>
emitNodeReaderWriterMethod(NodeClass node,const ReaderWriterInfo & info)413480093f4SDimitry Andric void ASTPropsEmitter::emitNodeReaderWriterMethod(NodeClass node,
414480093f4SDimitry Andric const ReaderWriterInfo &info) {
415480093f4SDimitry Andric // Declare and start the method.
416480093f4SDimitry Andric Out << " " << info.ResultType << " "
417480093f4SDimitry Andric << info.MethodPrefix << node.getClassName() << "(";
418480093f4SDimitry Andric if (!info.IsReader)
419480093f4SDimitry Andric Out << "const " << node.getClassName() << " *node";
420480093f4SDimitry Andric Out << ") {\n";
421480093f4SDimitry Andric if (info.IsReader)
422480093f4SDimitry Andric Out << " auto &ctx = " << info.HelperVariable << ".getASTContext();\n";
423480093f4SDimitry Andric
424480093f4SDimitry Andric emitPropertiedReaderWriterBody(node, info);
425480093f4SDimitry Andric
426480093f4SDimitry Andric // Finish the method declaration.
427480093f4SDimitry Andric Out << " }\n\n";
428480093f4SDimitry Andric }
429480093f4SDimitry Andric
emitPropertiedReaderWriterBody(HasProperties node,const ReaderWriterInfo & info)430480093f4SDimitry Andric void ASTPropsEmitter::emitPropertiedReaderWriterBody(HasProperties node,
431480093f4SDimitry Andric const ReaderWriterInfo &info) {
432480093f4SDimitry Andric // Find the information for this node.
433480093f4SDimitry Andric auto it = NodeInfos.find(node);
434480093f4SDimitry Andric if (it == NodeInfos.end())
435480093f4SDimitry Andric PrintFatalError(node.getLoc(),
436480093f4SDimitry Andric "no information about how to deserialize \""
437480093f4SDimitry Andric + node.getName() + "\"");
438480093f4SDimitry Andric auto &nodeInfo = it->second;
439480093f4SDimitry Andric
440480093f4SDimitry Andric StringRef creationCode;
441480093f4SDimitry Andric if (info.IsReader) {
442480093f4SDimitry Andric // We should have a creation rule.
443480093f4SDimitry Andric if (!nodeInfo.Creator)
444480093f4SDimitry Andric PrintFatalError(node.getLoc(),
445480093f4SDimitry Andric "no " CreationRuleClassName " for \""
446480093f4SDimitry Andric + node.getName() + "\"");
447480093f4SDimitry Andric
448480093f4SDimitry Andric creationCode = nodeInfo.Creator.getCreationCode();
449480093f4SDimitry Andric }
450480093f4SDimitry Andric
451480093f4SDimitry Andric // Emit the ReadHelper code, if present.
452480093f4SDimitry Andric if (!info.IsReader && nodeInfo.ReadHelper) {
453480093f4SDimitry Andric Out << " " << nodeInfo.ReadHelper.getHelperCode() << "\n";
454480093f4SDimitry Andric }
455480093f4SDimitry Andric
456480093f4SDimitry Andric // Emit code to read all the properties.
457480093f4SDimitry Andric visitAllProperties(node, nodeInfo, [&](Property prop) {
458480093f4SDimitry Andric // Verify that the creation code refers to this property.
459349cc55cSDimitry Andric if (info.IsReader && !creationCode.contains(prop.getName()))
460480093f4SDimitry Andric PrintFatalError(nodeInfo.Creator.getLoc(),
461480093f4SDimitry Andric "creation code for " + node.getName()
462480093f4SDimitry Andric + " doesn't refer to property \""
463480093f4SDimitry Andric + prop.getName() + "\"");
464480093f4SDimitry Andric
465480093f4SDimitry Andric // Emit code to read or write this property.
466480093f4SDimitry Andric if (info.IsReader)
467480093f4SDimitry Andric emitReadOfProperty(info.HelperVariable, prop);
468480093f4SDimitry Andric else
469480093f4SDimitry Andric emitWriteOfProperty(info.HelperVariable, prop);
470480093f4SDimitry Andric });
471480093f4SDimitry Andric
472480093f4SDimitry Andric // Emit the final creation code.
473480093f4SDimitry Andric if (info.IsReader)
474480093f4SDimitry Andric Out << " " << creationCode << "\n";
475480093f4SDimitry Andric }
476480093f4SDimitry Andric
emitBasicReaderWriterMethodSuffix(raw_ostream & out,PropertyType type,bool isForRead)477480093f4SDimitry Andric static void emitBasicReaderWriterMethodSuffix(raw_ostream &out,
478480093f4SDimitry Andric PropertyType type,
479480093f4SDimitry Andric bool isForRead) {
480480093f4SDimitry Andric if (!type.isGenericSpecialization()) {
481480093f4SDimitry Andric out << type.getAbstractTypeName();
482480093f4SDimitry Andric } else if (auto eltType = type.getArrayElementType()) {
483480093f4SDimitry Andric out << "Array";
484480093f4SDimitry Andric // We only include an explicit template argument for reads so that
485480093f4SDimitry Andric // we don't cause spurious const mismatches.
486480093f4SDimitry Andric if (isForRead) {
487480093f4SDimitry Andric out << "<";
488480093f4SDimitry Andric eltType.emitCXXValueTypeName(isForRead, out);
489480093f4SDimitry Andric out << ">";
490480093f4SDimitry Andric }
491480093f4SDimitry Andric } else if (auto valueType = type.getOptionalElementType()) {
492480093f4SDimitry Andric out << "Optional";
493480093f4SDimitry Andric // We only include an explicit template argument for reads so that
494480093f4SDimitry Andric // we don't cause spurious const mismatches.
495480093f4SDimitry Andric if (isForRead) {
496480093f4SDimitry Andric out << "<";
497480093f4SDimitry Andric valueType.emitCXXValueTypeName(isForRead, out);
498480093f4SDimitry Andric out << ">";
499480093f4SDimitry Andric }
500480093f4SDimitry Andric } else {
501480093f4SDimitry Andric PrintFatalError(type.getLoc(), "unexpected generic property type");
502480093f4SDimitry Andric }
503480093f4SDimitry Andric }
504480093f4SDimitry Andric
505480093f4SDimitry Andric /// Emit code to read the given property in a node-reader method.
emitReadOfProperty(StringRef readerName,Property property)506480093f4SDimitry Andric void ASTPropsEmitter::emitReadOfProperty(StringRef readerName,
507480093f4SDimitry Andric Property property) {
508480093f4SDimitry Andric emitReadOfProperty(readerName, property.getName(), property.getType(),
509480093f4SDimitry Andric property.getCondition());
510480093f4SDimitry Andric }
511480093f4SDimitry Andric
emitReadOfProperty(StringRef readerName,StringRef name,PropertyType type,StringRef condition)512480093f4SDimitry Andric void ASTPropsEmitter::emitReadOfProperty(StringRef readerName,
513480093f4SDimitry Andric StringRef name,
514480093f4SDimitry Andric PropertyType type,
515480093f4SDimitry Andric StringRef condition) {
516480093f4SDimitry Andric // Declare all the necessary buffers.
517480093f4SDimitry Andric auto bufferTypes = type.getBufferElementTypes();
518480093f4SDimitry Andric for (size_t i = 0, e = bufferTypes.size(); i != e; ++i) {
519480093f4SDimitry Andric Out << " llvm::SmallVector<";
520480093f4SDimitry Andric PropertyType(bufferTypes[i]).emitCXXValueTypeName(/*for read*/ true, Out);
521480093f4SDimitry Andric Out << ", 8> " << name << "_buffer_" << i << ";\n";
522480093f4SDimitry Andric }
523480093f4SDimitry Andric
524480093f4SDimitry Andric // T prop = R.find("prop").read##ValueType(buffers...);
525480093f4SDimitry Andric // We intentionally ignore shouldPassByReference here: we're going to
526480093f4SDimitry Andric // get a pr-value back from read(), and we should be able to forward
527480093f4SDimitry Andric // that in the creation rule.
528480093f4SDimitry Andric Out << " ";
529bdd1243dSDimitry Andric if (!condition.empty())
530bdd1243dSDimitry Andric Out << "std::optional<";
531480093f4SDimitry Andric type.emitCXXValueTypeName(true, Out);
532480093f4SDimitry Andric if (!condition.empty()) Out << ">";
533480093f4SDimitry Andric Out << " " << name;
534480093f4SDimitry Andric
535480093f4SDimitry Andric if (condition.empty()) {
536480093f4SDimitry Andric Out << " = ";
537480093f4SDimitry Andric } else {
538480093f4SDimitry Andric Out << ";\n"
539480093f4SDimitry Andric " if (" << condition << ") {\n"
540480093f4SDimitry Andric " " << name << ".emplace(";
541480093f4SDimitry Andric }
542480093f4SDimitry Andric
543480093f4SDimitry Andric Out << readerName << ".find(\"" << name << "\")."
544480093f4SDimitry Andric << (type.isGenericSpecialization() ? "template " : "") << "read";
545480093f4SDimitry Andric emitBasicReaderWriterMethodSuffix(Out, type, /*for read*/ true);
546480093f4SDimitry Andric Out << "(";
547480093f4SDimitry Andric for (size_t i = 0, e = bufferTypes.size(); i != e; ++i) {
548480093f4SDimitry Andric Out << (i > 0 ? ", " : "") << name << "_buffer_" << i;
549480093f4SDimitry Andric }
550480093f4SDimitry Andric Out << ")";
551480093f4SDimitry Andric
552480093f4SDimitry Andric if (condition.empty()) {
553480093f4SDimitry Andric Out << ";\n";
554480093f4SDimitry Andric } else {
555480093f4SDimitry Andric Out << ");\n"
556480093f4SDimitry Andric " }\n";
557480093f4SDimitry Andric }
558480093f4SDimitry Andric }
559480093f4SDimitry Andric
560480093f4SDimitry Andric /// Emit code to write the given property in a node-writer method.
emitWriteOfProperty(StringRef writerName,Property property)561480093f4SDimitry Andric void ASTPropsEmitter::emitWriteOfProperty(StringRef writerName,
562480093f4SDimitry Andric Property property) {
563480093f4SDimitry Andric emitWriteOfProperty(writerName, property.getName(), property.getType(),
564480093f4SDimitry Andric property.getReadCode(), property.getCondition());
565480093f4SDimitry Andric }
566480093f4SDimitry Andric
emitWriteOfProperty(StringRef writerName,StringRef name,PropertyType type,StringRef readCode,StringRef condition)567480093f4SDimitry Andric void ASTPropsEmitter::emitWriteOfProperty(StringRef writerName,
568480093f4SDimitry Andric StringRef name,
569480093f4SDimitry Andric PropertyType type,
570480093f4SDimitry Andric StringRef readCode,
571480093f4SDimitry Andric StringRef condition) {
572480093f4SDimitry Andric if (!condition.empty()) {
573480093f4SDimitry Andric Out << " if (" << condition << ") {\n";
574480093f4SDimitry Andric }
575480093f4SDimitry Andric
576480093f4SDimitry Andric // Focus down to the property:
577480093f4SDimitry Andric // T prop = <READ>;
578480093f4SDimitry Andric // W.find("prop").write##ValueType(prop);
579480093f4SDimitry Andric Out << " ";
580480093f4SDimitry Andric type.emitCXXValueTypeName(false, Out);
581480093f4SDimitry Andric Out << " " << name << " = (" << readCode << ");\n"
582480093f4SDimitry Andric " " << writerName << ".find(\"" << name << "\").write";
583480093f4SDimitry Andric emitBasicReaderWriterMethodSuffix(Out, type, /*for read*/ false);
584480093f4SDimitry Andric Out << "(" << name << ");\n";
585480093f4SDimitry Andric
586480093f4SDimitry Andric if (!condition.empty()) {
587480093f4SDimitry Andric Out << " }\n";
588480093f4SDimitry Andric }
589480093f4SDimitry Andric }
590480093f4SDimitry Andric
591480093f4SDimitry Andric /// Emit an .inc file that defines the AbstractFooReader class
592480093f4SDimitry Andric /// for the given AST class hierarchy.
593480093f4SDimitry Andric template <class NodeClass>
emitASTReader(RecordKeeper & records,raw_ostream & out,StringRef description)594480093f4SDimitry Andric static void emitASTReader(RecordKeeper &records, raw_ostream &out,
595480093f4SDimitry Andric StringRef description) {
596*5f757f3fSDimitry Andric emitSourceFileHeader(description, out, records);
597480093f4SDimitry Andric
598480093f4SDimitry Andric ASTPropsEmitter(records, out).emitNodeReaderClass<NodeClass>();
599480093f4SDimitry Andric }
600480093f4SDimitry Andric
EmitClangTypeReader(RecordKeeper & records,raw_ostream & out)601480093f4SDimitry Andric void clang::EmitClangTypeReader(RecordKeeper &records, raw_ostream &out) {
602480093f4SDimitry Andric emitASTReader<TypeNode>(records, out, "A CRTP reader for Clang Type nodes");
603480093f4SDimitry Andric }
604480093f4SDimitry Andric
605480093f4SDimitry Andric /// Emit an .inc file that defines the AbstractFooWriter class
606480093f4SDimitry Andric /// for the given AST class hierarchy.
607480093f4SDimitry Andric template <class NodeClass>
emitASTWriter(RecordKeeper & records,raw_ostream & out,StringRef description)608480093f4SDimitry Andric static void emitASTWriter(RecordKeeper &records, raw_ostream &out,
609480093f4SDimitry Andric StringRef description) {
610*5f757f3fSDimitry Andric emitSourceFileHeader(description, out, records);
611480093f4SDimitry Andric
612480093f4SDimitry Andric ASTPropsEmitter(records, out).emitNodeWriterClass<NodeClass>();
613480093f4SDimitry Andric }
614480093f4SDimitry Andric
EmitClangTypeWriter(RecordKeeper & records,raw_ostream & out)615480093f4SDimitry Andric void clang::EmitClangTypeWriter(RecordKeeper &records, raw_ostream &out) {
616480093f4SDimitry Andric emitASTWriter<TypeNode>(records, out, "A CRTP writer for Clang Type nodes");
617480093f4SDimitry Andric }
618480093f4SDimitry Andric
619480093f4SDimitry Andric /****************************************************************************/
620480093f4SDimitry Andric /*************************** BASIC READER/WRITERS ***************************/
621480093f4SDimitry Andric /****************************************************************************/
622480093f4SDimitry Andric
623480093f4SDimitry Andric void
emitDispatcherTemplate(const ReaderWriterInfo & info)624480093f4SDimitry Andric ASTPropsEmitter::emitDispatcherTemplate(const ReaderWriterInfo &info) {
625480093f4SDimitry Andric // Declare the {Read,Write}Dispatcher template.
626480093f4SDimitry Andric StringRef dispatcherPrefix = (info.IsReader ? "Read" : "Write");
627480093f4SDimitry Andric Out << "template <class ValueType>\n"
628480093f4SDimitry Andric "struct " << dispatcherPrefix << "Dispatcher;\n";
629480093f4SDimitry Andric
630480093f4SDimitry Andric // Declare a specific specialization of the dispatcher template.
631480093f4SDimitry Andric auto declareSpecialization =
632480093f4SDimitry Andric [&](StringRef specializationParameters,
633480093f4SDimitry Andric const Twine &cxxTypeName,
634480093f4SDimitry Andric StringRef methodSuffix) {
635480093f4SDimitry Andric StringRef var = info.HelperVariable;
636480093f4SDimitry Andric Out << "template " << specializationParameters << "\n"
637480093f4SDimitry Andric "struct " << dispatcherPrefix << "Dispatcher<"
638480093f4SDimitry Andric << cxxTypeName << "> {\n";
639480093f4SDimitry Andric Out << " template <class Basic" << info.ClassSuffix << ", class... Args>\n"
640480093f4SDimitry Andric " static " << (info.IsReader ? cxxTypeName : "void") << " "
641480093f4SDimitry Andric << info.MethodPrefix
642480093f4SDimitry Andric << "(Basic" << info.ClassSuffix << " &" << var
643480093f4SDimitry Andric << ", Args &&... args) {\n"
644480093f4SDimitry Andric " return " << var << "."
645480093f4SDimitry Andric << info.MethodPrefix << methodSuffix
646480093f4SDimitry Andric << "(std::forward<Args>(args)...);\n"
647480093f4SDimitry Andric " }\n"
648480093f4SDimitry Andric "};\n";
649480093f4SDimitry Andric };
650480093f4SDimitry Andric
651480093f4SDimitry Andric // Declare explicit specializations for each of the concrete types.
652480093f4SDimitry Andric for (PropertyType type : AllPropertyTypes) {
653480093f4SDimitry Andric declareSpecialization("<>",
654480093f4SDimitry Andric type.getCXXTypeName(),
655480093f4SDimitry Andric type.getAbstractTypeName());
656480093f4SDimitry Andric // Also declare a specialization for the const type when appropriate.
657480093f4SDimitry Andric if (!info.IsReader && type.isConstWhenWriting()) {
658480093f4SDimitry Andric declareSpecialization("<>",
659480093f4SDimitry Andric "const " + type.getCXXTypeName(),
660480093f4SDimitry Andric type.getAbstractTypeName());
661480093f4SDimitry Andric }
662480093f4SDimitry Andric }
663480093f4SDimitry Andric // Declare partial specializations for ArrayRef and Optional.
664480093f4SDimitry Andric declareSpecialization("<class T>",
665480093f4SDimitry Andric "llvm::ArrayRef<T>",
666480093f4SDimitry Andric "Array");
667bdd1243dSDimitry Andric declareSpecialization("<class T>", "std::optional<T>", "Optional");
668480093f4SDimitry Andric Out << "\n";
669480093f4SDimitry Andric }
670480093f4SDimitry Andric
671480093f4SDimitry Andric void
emitPackUnpackOptionalTemplate(const ReaderWriterInfo & info)672480093f4SDimitry Andric ASTPropsEmitter::emitPackUnpackOptionalTemplate(const ReaderWriterInfo &info) {
673480093f4SDimitry Andric StringRef classPrefix = (info.IsReader ? "Unpack" : "Pack");
674480093f4SDimitry Andric StringRef methodName = (info.IsReader ? "unpack" : "pack");
675480093f4SDimitry Andric
676480093f4SDimitry Andric // Declare the {Pack,Unpack}OptionalValue template.
677480093f4SDimitry Andric Out << "template <class ValueType>\n"
678480093f4SDimitry Andric "struct " << classPrefix << "OptionalValue;\n";
679480093f4SDimitry Andric
680bdd1243dSDimitry Andric auto declareSpecialization = [&](const Twine &typeName, StringRef code) {
681480093f4SDimitry Andric Out << "template <>\n"
682bdd1243dSDimitry Andric "struct "
683bdd1243dSDimitry Andric << classPrefix << "OptionalValue<" << typeName
684bdd1243dSDimitry Andric << "> {\n"
685bdd1243dSDimitry Andric " static "
686bdd1243dSDimitry Andric << (info.IsReader ? "std::optional<" : "") << typeName
687480093f4SDimitry Andric << (info.IsReader ? "> " : " ") << methodName << "("
688bdd1243dSDimitry Andric << (info.IsReader ? "" : "std::optional<") << typeName
689bdd1243dSDimitry Andric << (info.IsReader ? "" : ">")
690bdd1243dSDimitry Andric << " value) {\n"
691bdd1243dSDimitry Andric " return "
692bdd1243dSDimitry Andric << code
693bdd1243dSDimitry Andric << ";\n"
694480093f4SDimitry Andric " }\n"
695480093f4SDimitry Andric "};\n";
696480093f4SDimitry Andric };
697480093f4SDimitry Andric
698480093f4SDimitry Andric for (PropertyType type : AllPropertyTypes) {
699480093f4SDimitry Andric StringRef code = (info.IsReader ? type.getUnpackOptionalCode()
700480093f4SDimitry Andric : type.getPackOptionalCode());
701480093f4SDimitry Andric if (code.empty()) continue;
702480093f4SDimitry Andric
703480093f4SDimitry Andric StringRef typeName = type.getCXXTypeName();
704480093f4SDimitry Andric declareSpecialization(typeName, code);
705480093f4SDimitry Andric if (type.isConstWhenWriting() && !info.IsReader)
706480093f4SDimitry Andric declareSpecialization("const " + typeName, code);
707480093f4SDimitry Andric }
708480093f4SDimitry Andric Out << "\n";
709480093f4SDimitry Andric }
710480093f4SDimitry Andric
711480093f4SDimitry Andric void
emitBasicReaderWriterTemplate(const ReaderWriterInfo & info)712480093f4SDimitry Andric ASTPropsEmitter::emitBasicReaderWriterTemplate(const ReaderWriterInfo &info) {
713480093f4SDimitry Andric // Emit the Basic{Reader,Writer}Base template.
714480093f4SDimitry Andric Out << "template <class Impl>\n"
715480093f4SDimitry Andric "class Basic" << info.ClassSuffix << "Base {\n";
716480093f4SDimitry Andric Out << " ASTContext &C;\n";
717480093f4SDimitry Andric Out << "protected:\n"
718e8d8bef9SDimitry Andric " Basic"
719e8d8bef9SDimitry Andric << info.ClassSuffix << "Base" << ("(ASTContext &ctx) : C(ctx)")
720480093f4SDimitry Andric << " {}\n"
721480093f4SDimitry Andric "public:\n";
722480093f4SDimitry Andric Out << " ASTContext &getASTContext() { return C; }\n";
723480093f4SDimitry Andric Out << " Impl &asImpl() { return static_cast<Impl&>(*this); }\n";
724480093f4SDimitry Andric
725480093f4SDimitry Andric auto enterReaderWriterMethod = [&](StringRef cxxTypeName,
726480093f4SDimitry Andric StringRef abstractTypeName,
727480093f4SDimitry Andric bool shouldPassByReference,
728480093f4SDimitry Andric bool constWhenWriting,
729480093f4SDimitry Andric StringRef paramName) {
730480093f4SDimitry Andric Out << " " << (info.IsReader ? cxxTypeName : "void")
731480093f4SDimitry Andric << " " << info.MethodPrefix << abstractTypeName << "(";
732480093f4SDimitry Andric if (!info.IsReader)
733480093f4SDimitry Andric Out << (shouldPassByReference || constWhenWriting ? "const " : "")
734480093f4SDimitry Andric << cxxTypeName
735480093f4SDimitry Andric << (shouldPassByReference ? " &" : "") << " " << paramName;
736480093f4SDimitry Andric Out << ") {\n";
737480093f4SDimitry Andric };
738480093f4SDimitry Andric
739480093f4SDimitry Andric // Emit {read,write}ValueType methods for all the enum and subclass types
740480093f4SDimitry Andric // that default to using the integer/base-class implementations.
741480093f4SDimitry Andric for (PropertyType type : AllPropertyTypes) {
742480093f4SDimitry Andric auto enterMethod = [&](StringRef paramName) {
743480093f4SDimitry Andric enterReaderWriterMethod(type.getCXXTypeName(),
744480093f4SDimitry Andric type.getAbstractTypeName(),
745480093f4SDimitry Andric type.shouldPassByReference(),
746480093f4SDimitry Andric type.isConstWhenWriting(),
747480093f4SDimitry Andric paramName);
748480093f4SDimitry Andric };
749480093f4SDimitry Andric auto exitMethod = [&] {
750480093f4SDimitry Andric Out << " }\n";
751480093f4SDimitry Andric };
752480093f4SDimitry Andric
753480093f4SDimitry Andric // Handled cased types.
754480093f4SDimitry Andric auto casedIter = CasedTypeInfos.find(type);
755480093f4SDimitry Andric if (casedIter != CasedTypeInfos.end()) {
756480093f4SDimitry Andric enterMethod("node");
757480093f4SDimitry Andric emitCasedReaderWriterMethodBody(type, casedIter->second, info);
758480093f4SDimitry Andric exitMethod();
759480093f4SDimitry Andric
760480093f4SDimitry Andric } else if (type.isEnum()) {
761480093f4SDimitry Andric enterMethod("value");
762480093f4SDimitry Andric if (info.IsReader)
763480093f4SDimitry Andric Out << " return asImpl().template readEnum<"
764480093f4SDimitry Andric << type.getCXXTypeName() << ">();\n";
765480093f4SDimitry Andric else
766480093f4SDimitry Andric Out << " asImpl().writeEnum(value);\n";
767480093f4SDimitry Andric exitMethod();
768480093f4SDimitry Andric
769480093f4SDimitry Andric } else if (PropertyType superclass = type.getSuperclassType()) {
770480093f4SDimitry Andric enterMethod("value");
771480093f4SDimitry Andric if (info.IsReader)
772480093f4SDimitry Andric Out << " return cast_or_null<" << type.getSubclassClassName()
773480093f4SDimitry Andric << ">(asImpl().read"
774480093f4SDimitry Andric << superclass.getAbstractTypeName()
775480093f4SDimitry Andric << "());\n";
776480093f4SDimitry Andric else
777480093f4SDimitry Andric Out << " asImpl().write" << superclass.getAbstractTypeName()
778480093f4SDimitry Andric << "(value);\n";
779480093f4SDimitry Andric exitMethod();
780480093f4SDimitry Andric
781480093f4SDimitry Andric } else {
782480093f4SDimitry Andric // The other types can't be handled as trivially.
783480093f4SDimitry Andric }
784480093f4SDimitry Andric }
785480093f4SDimitry Andric Out << "};\n\n";
786480093f4SDimitry Andric }
787480093f4SDimitry Andric
emitCasedReaderWriterMethodBody(PropertyType type,const CasedTypeInfo & typeCases,const ReaderWriterInfo & info)788480093f4SDimitry Andric void ASTPropsEmitter::emitCasedReaderWriterMethodBody(PropertyType type,
789480093f4SDimitry Andric const CasedTypeInfo &typeCases,
790480093f4SDimitry Andric const ReaderWriterInfo &info) {
791480093f4SDimitry Andric if (typeCases.Cases.empty()) {
792480093f4SDimitry Andric assert(typeCases.KindRule);
793480093f4SDimitry Andric PrintFatalError(typeCases.KindRule.getLoc(),
794480093f4SDimitry Andric "no cases found for \"" + type.getCXXTypeName() + "\"");
795480093f4SDimitry Andric }
796480093f4SDimitry Andric if (!typeCases.KindRule) {
797480093f4SDimitry Andric assert(!typeCases.Cases.empty());
798480093f4SDimitry Andric PrintFatalError(typeCases.Cases.front().getLoc(),
799480093f4SDimitry Andric "no kind rule for \"" + type.getCXXTypeName() + "\"");
800480093f4SDimitry Andric }
801480093f4SDimitry Andric
802480093f4SDimitry Andric auto var = info.HelperVariable;
803480093f4SDimitry Andric std::string subvar = ("sub" + var).str();
804480093f4SDimitry Andric
805480093f4SDimitry Andric // Bind `ctx` for readers.
806480093f4SDimitry Andric if (info.IsReader)
807480093f4SDimitry Andric Out << " auto &ctx = asImpl().getASTContext();\n";
808480093f4SDimitry Andric
809480093f4SDimitry Andric // Start an object.
810480093f4SDimitry Andric Out << " auto &&" << subvar << " = asImpl()."
811480093f4SDimitry Andric << info.MethodPrefix << "Object();\n";
812480093f4SDimitry Andric
813480093f4SDimitry Andric // Read/write the kind property;
814480093f4SDimitry Andric TypeKindRule kindRule = typeCases.KindRule;
815480093f4SDimitry Andric StringRef kindProperty = kindRule.getKindPropertyName();
816480093f4SDimitry Andric PropertyType kindType = kindRule.getKindType();
817480093f4SDimitry Andric if (info.IsReader) {
818480093f4SDimitry Andric emitReadOfProperty(subvar, kindProperty, kindType);
819480093f4SDimitry Andric } else {
820480093f4SDimitry Andric // Write the property. Note that this will implicitly read the
821480093f4SDimitry Andric // kind into a local variable with the right name.
822480093f4SDimitry Andric emitWriteOfProperty(subvar, kindProperty, kindType,
823480093f4SDimitry Andric kindRule.getReadCode());
824480093f4SDimitry Andric }
825480093f4SDimitry Andric
826480093f4SDimitry Andric // Prepare a ReaderWriterInfo with a helper variable that will use
827480093f4SDimitry Andric // the sub-reader/writer.
828480093f4SDimitry Andric ReaderWriterInfo subInfo = info;
829480093f4SDimitry Andric subInfo.HelperVariable = subvar;
830480093f4SDimitry Andric
831480093f4SDimitry Andric // Switch on the kind.
832480093f4SDimitry Andric Out << " switch (" << kindProperty << ") {\n";
833480093f4SDimitry Andric for (TypeCase typeCase : typeCases.Cases) {
834480093f4SDimitry Andric Out << " case " << type.getCXXTypeName() << "::"
835480093f4SDimitry Andric << typeCase.getCaseName() << ": {\n";
836480093f4SDimitry Andric emitPropertiedReaderWriterBody(typeCase, subInfo);
837480093f4SDimitry Andric if (!info.IsReader)
838480093f4SDimitry Andric Out << " return;\n";
839480093f4SDimitry Andric Out << " }\n\n";
840480093f4SDimitry Andric }
841480093f4SDimitry Andric Out << " }\n"
842480093f4SDimitry Andric " llvm_unreachable(\"bad " << kindType.getCXXTypeName()
843480093f4SDimitry Andric << "\");\n";
844480093f4SDimitry Andric }
845480093f4SDimitry Andric
emitBasicReaderWriterFile(const ReaderWriterInfo & info)846480093f4SDimitry Andric void ASTPropsEmitter::emitBasicReaderWriterFile(const ReaderWriterInfo &info) {
847480093f4SDimitry Andric emitDispatcherTemplate(info);
848480093f4SDimitry Andric emitPackUnpackOptionalTemplate(info);
849480093f4SDimitry Andric emitBasicReaderWriterTemplate(info);
850480093f4SDimitry Andric }
851480093f4SDimitry Andric
852480093f4SDimitry Andric /// Emit an .inc file that defines some helper classes for reading
853480093f4SDimitry Andric /// basic values.
EmitClangBasicReader(RecordKeeper & records,raw_ostream & out)854480093f4SDimitry Andric void clang::EmitClangBasicReader(RecordKeeper &records, raw_ostream &out) {
855*5f757f3fSDimitry Andric emitSourceFileHeader("Helper classes for BasicReaders", out, records);
856480093f4SDimitry Andric
857480093f4SDimitry Andric // Use any property, we won't be using those properties.
858480093f4SDimitry Andric auto info = ReaderWriterInfo::forReader<TypeNode>();
859480093f4SDimitry Andric ASTPropsEmitter(records, out).emitBasicReaderWriterFile(info);
860480093f4SDimitry Andric }
861480093f4SDimitry Andric
862480093f4SDimitry Andric /// Emit an .inc file that defines some helper classes for writing
863480093f4SDimitry Andric /// basic values.
EmitClangBasicWriter(RecordKeeper & records,raw_ostream & out)864480093f4SDimitry Andric void clang::EmitClangBasicWriter(RecordKeeper &records, raw_ostream &out) {
865*5f757f3fSDimitry Andric emitSourceFileHeader("Helper classes for BasicWriters", out, records);
866480093f4SDimitry Andric
867480093f4SDimitry Andric // Use any property, we won't be using those properties.
868480093f4SDimitry Andric auto info = ReaderWriterInfo::forWriter<TypeNode>();
869480093f4SDimitry Andric ASTPropsEmitter(records, out).emitBasicReaderWriterFile(info);
870480093f4SDimitry Andric }
871