Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/clang/utils/TableGen/ClangASTPropertiesEmitter.cpp
35230 views
1
//=== ClangASTPropsEmitter.cpp - Generate Clang AST properties --*- C++ -*-===//
2
//
3
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4
// See https://llvm.org/LICENSE.txt for license information.
5
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
//
7
//===----------------------------------------------------------------------===//
8
//
9
// This tablegen backend emits code for working with Clang AST properties.
10
//
11
//===----------------------------------------------------------------------===//
12
13
#include "ASTTableGen.h"
14
#include "TableGenBackends.h"
15
16
#include "llvm/ADT/STLExtras.h"
17
#include "llvm/ADT/Twine.h"
18
#include "llvm/TableGen/Error.h"
19
#include "llvm/TableGen/Record.h"
20
#include "llvm/TableGen/TableGenBackend.h"
21
#include <cctype>
22
#include <map>
23
#include <optional>
24
#include <set>
25
#include <string>
26
using namespace llvm;
27
using namespace clang;
28
using namespace clang::tblgen;
29
30
static StringRef getReaderResultType(TypeNode _) { return "QualType"; }
31
32
namespace {
33
34
struct ReaderWriterInfo {
35
bool IsReader;
36
37
/// The name of the node hierarchy. Not actually sensitive to IsReader,
38
/// but useful to cache here anyway.
39
StringRef HierarchyName;
40
41
/// The suffix on classes: Reader/Writer
42
StringRef ClassSuffix;
43
44
/// The base name of methods: read/write
45
StringRef MethodPrefix;
46
47
/// The name of the property helper member: R/W
48
StringRef HelperVariable;
49
50
/// The result type of methods on the class.
51
StringRef ResultType;
52
53
template <class NodeClass>
54
static ReaderWriterInfo forReader() {
55
return ReaderWriterInfo{
56
true,
57
NodeClass::getASTHierarchyName(),
58
"Reader",
59
"read",
60
"R",
61
getReaderResultType(NodeClass())
62
};
63
}
64
65
template <class NodeClass>
66
static ReaderWriterInfo forWriter() {
67
return ReaderWriterInfo{
68
false,
69
NodeClass::getASTHierarchyName(),
70
"Writer",
71
"write",
72
"W",
73
"void"
74
};
75
}
76
};
77
78
struct NodeInfo {
79
std::vector<Property> Properties;
80
CreationRule Creator = nullptr;
81
OverrideRule Override = nullptr;
82
ReadHelperRule ReadHelper = nullptr;
83
};
84
85
struct CasedTypeInfo {
86
TypeKindRule KindRule;
87
std::vector<TypeCase> Cases;
88
};
89
90
class ASTPropsEmitter {
91
raw_ostream &Out;
92
RecordKeeper &Records;
93
std::map<HasProperties, NodeInfo> NodeInfos;
94
std::vector<PropertyType> AllPropertyTypes;
95
std::map<PropertyType, CasedTypeInfo> CasedTypeInfos;
96
97
public:
98
ASTPropsEmitter(RecordKeeper &records, raw_ostream &out)
99
: Out(out), Records(records) {
100
101
// Find all the properties.
102
for (Property property :
103
records.getAllDerivedDefinitions(PropertyClassName)) {
104
HasProperties node = property.getClass();
105
NodeInfos[node].Properties.push_back(property);
106
}
107
108
// Find all the creation rules.
109
for (CreationRule creationRule :
110
records.getAllDerivedDefinitions(CreationRuleClassName)) {
111
HasProperties node = creationRule.getClass();
112
113
auto &info = NodeInfos[node];
114
if (info.Creator) {
115
PrintFatalError(creationRule.getLoc(),
116
"multiple creator rules for \"" + node.getName()
117
+ "\"");
118
}
119
info.Creator = creationRule;
120
}
121
122
// Find all the override rules.
123
for (OverrideRule overrideRule :
124
records.getAllDerivedDefinitions(OverrideRuleClassName)) {
125
HasProperties node = overrideRule.getClass();
126
127
auto &info = NodeInfos[node];
128
if (info.Override) {
129
PrintFatalError(overrideRule.getLoc(),
130
"multiple override rules for \"" + node.getName()
131
+ "\"");
132
}
133
info.Override = overrideRule;
134
}
135
136
// Find all the write helper rules.
137
for (ReadHelperRule helperRule :
138
records.getAllDerivedDefinitions(ReadHelperRuleClassName)) {
139
HasProperties node = helperRule.getClass();
140
141
auto &info = NodeInfos[node];
142
if (info.ReadHelper) {
143
PrintFatalError(helperRule.getLoc(),
144
"multiple write helper rules for \"" + node.getName()
145
+ "\"");
146
}
147
info.ReadHelper = helperRule;
148
}
149
150
// Find all the concrete property types.
151
for (PropertyType type :
152
records.getAllDerivedDefinitions(PropertyTypeClassName)) {
153
// Ignore generic specializations; they're generally not useful when
154
// emitting basic emitters etc.
155
if (type.isGenericSpecialization()) continue;
156
157
AllPropertyTypes.push_back(type);
158
}
159
160
// Find all the type kind rules.
161
for (TypeKindRule kindRule :
162
records.getAllDerivedDefinitions(TypeKindClassName)) {
163
PropertyType type = kindRule.getParentType();
164
auto &info = CasedTypeInfos[type];
165
if (info.KindRule) {
166
PrintFatalError(kindRule.getLoc(),
167
"multiple kind rules for \""
168
+ type.getCXXTypeName() + "\"");
169
}
170
info.KindRule = kindRule;
171
}
172
173
// Find all the type cases.
174
for (TypeCase typeCase :
175
records.getAllDerivedDefinitions(TypeCaseClassName)) {
176
CasedTypeInfos[typeCase.getParentType()].Cases.push_back(typeCase);
177
}
178
179
Validator(*this).validate();
180
}
181
182
void visitAllProperties(HasProperties derived, const NodeInfo &derivedInfo,
183
function_ref<void (Property)> visit) {
184
std::set<StringRef> ignoredProperties;
185
186
auto overrideRule = derivedInfo.Override;
187
if (overrideRule) {
188
auto list = overrideRule.getIgnoredProperties();
189
ignoredProperties.insert(list.begin(), list.end());
190
}
191
192
// TODO: we should sort the properties in various ways
193
// - put arrays at the end to enable abbreviations
194
// - put conditional properties after properties used in the condition
195
196
visitAllNodesWithInfo(derived, derivedInfo,
197
[&](HasProperties node, const NodeInfo &info) {
198
for (Property prop : info.Properties) {
199
if (ignoredProperties.count(prop.getName()))
200
continue;
201
202
visit(prop);
203
}
204
});
205
}
206
207
void visitAllNodesWithInfo(HasProperties derivedNode,
208
const NodeInfo &derivedNodeInfo,
209
llvm::function_ref<void (HasProperties node,
210
const NodeInfo &info)>
211
visit) {
212
visit(derivedNode, derivedNodeInfo);
213
214
// Also walk the bases if appropriate.
215
if (ASTNode base = derivedNode.getAs<ASTNode>()) {
216
for (base = base.getBase(); base; base = base.getBase()) {
217
auto it = NodeInfos.find(base);
218
219
// Ignore intermediate nodes that don't add interesting properties.
220
if (it == NodeInfos.end()) continue;
221
auto &baseInfo = it->second;
222
223
visit(base, baseInfo);
224
}
225
}
226
}
227
228
template <class NodeClass>
229
void emitNodeReaderClass() {
230
auto info = ReaderWriterInfo::forReader<NodeClass>();
231
emitNodeReaderWriterClass<NodeClass>(info);
232
}
233
234
template <class NodeClass>
235
void emitNodeWriterClass() {
236
auto info = ReaderWriterInfo::forWriter<NodeClass>();
237
emitNodeReaderWriterClass<NodeClass>(info);
238
}
239
240
template <class NodeClass>
241
void emitNodeReaderWriterClass(const ReaderWriterInfo &info);
242
243
template <class NodeClass>
244
void emitNodeReaderWriterMethod(NodeClass node,
245
const ReaderWriterInfo &info);
246
247
void emitPropertiedReaderWriterBody(HasProperties node,
248
const ReaderWriterInfo &info);
249
250
void emitReadOfProperty(StringRef readerName, Property property);
251
void emitReadOfProperty(StringRef readerName, StringRef name,
252
PropertyType type, StringRef condition = "");
253
254
void emitWriteOfProperty(StringRef writerName, Property property);
255
void emitWriteOfProperty(StringRef writerName, StringRef name,
256
PropertyType type, StringRef readCode,
257
StringRef condition = "");
258
259
void emitBasicReaderWriterFile(const ReaderWriterInfo &info);
260
void emitDispatcherTemplate(const ReaderWriterInfo &info);
261
void emitPackUnpackOptionalTemplate(const ReaderWriterInfo &info);
262
void emitBasicReaderWriterTemplate(const ReaderWriterInfo &info);
263
264
void emitCasedReaderWriterMethodBody(PropertyType type,
265
const CasedTypeInfo &typeCases,
266
const ReaderWriterInfo &info);
267
268
private:
269
class Validator {
270
ASTPropsEmitter &Emitter;
271
std::set<HasProperties> ValidatedNodes;
272
273
public:
274
Validator(ASTPropsEmitter &emitter) : Emitter(emitter) {}
275
void validate();
276
277
private:
278
void validateNode(HasProperties node, const NodeInfo &nodeInfo);
279
void validateType(PropertyType type, WrappedRecord context);
280
};
281
};
282
283
} // end anonymous namespace
284
285
void ASTPropsEmitter::Validator::validate() {
286
for (auto &entry : Emitter.NodeInfos) {
287
validateNode(entry.first, entry.second);
288
}
289
290
if (ErrorsPrinted > 0) {
291
PrintFatalError("property validation failed");
292
}
293
}
294
295
void ASTPropsEmitter::Validator::validateNode(HasProperties derivedNode,
296
const NodeInfo &derivedNodeInfo) {
297
if (!ValidatedNodes.insert(derivedNode).second) return;
298
299
// A map from property name to property.
300
std::map<StringRef, Property> allProperties;
301
302
Emitter.visitAllNodesWithInfo(derivedNode, derivedNodeInfo,
303
[&](HasProperties node,
304
const NodeInfo &nodeInfo) {
305
for (Property property : nodeInfo.Properties) {
306
validateType(property.getType(), property);
307
308
auto result = allProperties.insert(
309
std::make_pair(property.getName(), property));
310
311
// Diagnose non-unique properties.
312
if (!result.second) {
313
// The existing property is more likely to be associated with a
314
// derived node, so use it as the error.
315
Property existingProperty = result.first->second;
316
PrintError(existingProperty.getLoc(),
317
"multiple properties named \"" + property.getName()
318
+ "\" in hierarchy of " + derivedNode.getName());
319
PrintNote(property.getLoc(), "existing property");
320
}
321
}
322
});
323
}
324
325
void ASTPropsEmitter::Validator::validateType(PropertyType type,
326
WrappedRecord context) {
327
if (!type.isGenericSpecialization()) {
328
if (type.getCXXTypeName() == "") {
329
PrintError(type.getLoc(),
330
"type is not generic but has no C++ type name");
331
if (context) PrintNote(context.getLoc(), "type used here");
332
}
333
} else if (auto eltType = type.getArrayElementType()) {
334
validateType(eltType, context);
335
} else if (auto valueType = type.getOptionalElementType()) {
336
validateType(valueType, context);
337
338
if (valueType.getPackOptionalCode().empty()) {
339
PrintError(valueType.getLoc(),
340
"type doesn't provide optional-packing code");
341
if (context) PrintNote(context.getLoc(), "type used here");
342
} else if (valueType.getUnpackOptionalCode().empty()) {
343
PrintError(valueType.getLoc(),
344
"type doesn't provide optional-unpacking code");
345
if (context) PrintNote(context.getLoc(), "type used here");
346
}
347
} else {
348
PrintError(type.getLoc(), "unknown generic property type");
349
if (context) PrintNote(context.getLoc(), "type used here");
350
}
351
}
352
353
/****************************************************************************/
354
/**************************** AST READER/WRITERS ****************************/
355
/****************************************************************************/
356
357
template <class NodeClass>
358
void ASTPropsEmitter::emitNodeReaderWriterClass(const ReaderWriterInfo &info) {
359
StringRef suffix = info.ClassSuffix;
360
StringRef var = info.HelperVariable;
361
362
// Enter the class declaration.
363
Out << "template <class Property" << suffix << ">\n"
364
"class Abstract" << info.HierarchyName << suffix << " {\n"
365
"public:\n"
366
" Property" << suffix << " &" << var << ";\n\n";
367
368
// Emit the constructor.
369
Out << " Abstract" << info.HierarchyName << suffix
370
<< "(Property" << suffix << " &" << var << ") : "
371
<< var << "(" << var << ") {}\n\n";
372
373
// Emit a method that dispatches on a kind to the appropriate node-specific
374
// method.
375
Out << " " << info.ResultType << " " << info.MethodPrefix << "(";
376
if (info.IsReader)
377
Out << NodeClass::getASTIdTypeName() << " kind";
378
else
379
Out << "const " << info.HierarchyName << " *node";
380
Out << ") {\n"
381
" switch (";
382
if (info.IsReader)
383
Out << "kind";
384
else
385
Out << "node->" << NodeClass::getASTIdAccessorName() << "()";
386
Out << ") {\n";
387
visitASTNodeHierarchy<NodeClass>(Records, [&](NodeClass node, NodeClass _) {
388
if (node.isAbstract()) return;
389
Out << " case " << info.HierarchyName << "::" << node.getId() << ":\n"
390
" return " << info.MethodPrefix << node.getClassName() << "(";
391
if (!info.IsReader)
392
Out << "static_cast<const " << node.getClassName()
393
<< " *>(node)";
394
Out << ");\n";
395
});
396
Out << " }\n"
397
" llvm_unreachable(\"bad kind\");\n"
398
" }\n\n";
399
400
// Emit node-specific methods for all the concrete nodes.
401
visitASTNodeHierarchy<NodeClass>(Records,
402
[&](NodeClass node, NodeClass base) {
403
if (node.isAbstract()) return;
404
emitNodeReaderWriterMethod(node, info);
405
});
406
407
// Finish the class.
408
Out << "};\n\n";
409
}
410
411
/// Emit a reader method for the given concrete AST node class.
412
template <class NodeClass>
413
void ASTPropsEmitter::emitNodeReaderWriterMethod(NodeClass node,
414
const ReaderWriterInfo &info) {
415
// Declare and start the method.
416
Out << " " << info.ResultType << " "
417
<< info.MethodPrefix << node.getClassName() << "(";
418
if (!info.IsReader)
419
Out << "const " << node.getClassName() << " *node";
420
Out << ") {\n";
421
if (info.IsReader)
422
Out << " auto &ctx = " << info.HelperVariable << ".getASTContext();\n";
423
424
emitPropertiedReaderWriterBody(node, info);
425
426
// Finish the method declaration.
427
Out << " }\n\n";
428
}
429
430
void ASTPropsEmitter::emitPropertiedReaderWriterBody(HasProperties node,
431
const ReaderWriterInfo &info) {
432
// Find the information for this node.
433
auto it = NodeInfos.find(node);
434
if (it == NodeInfos.end())
435
PrintFatalError(node.getLoc(),
436
"no information about how to deserialize \""
437
+ node.getName() + "\"");
438
auto &nodeInfo = it->second;
439
440
StringRef creationCode;
441
if (info.IsReader) {
442
// We should have a creation rule.
443
if (!nodeInfo.Creator)
444
PrintFatalError(node.getLoc(),
445
"no " CreationRuleClassName " for \""
446
+ node.getName() + "\"");
447
448
creationCode = nodeInfo.Creator.getCreationCode();
449
}
450
451
// Emit the ReadHelper code, if present.
452
if (!info.IsReader && nodeInfo.ReadHelper) {
453
Out << " " << nodeInfo.ReadHelper.getHelperCode() << "\n";
454
}
455
456
// Emit code to read all the properties.
457
visitAllProperties(node, nodeInfo, [&](Property prop) {
458
// Verify that the creation code refers to this property.
459
if (info.IsReader && !creationCode.contains(prop.getName()))
460
PrintFatalError(nodeInfo.Creator.getLoc(),
461
"creation code for " + node.getName()
462
+ " doesn't refer to property \""
463
+ prop.getName() + "\"");
464
465
// Emit code to read or write this property.
466
if (info.IsReader)
467
emitReadOfProperty(info.HelperVariable, prop);
468
else
469
emitWriteOfProperty(info.HelperVariable, prop);
470
});
471
472
// Emit the final creation code.
473
if (info.IsReader)
474
Out << " " << creationCode << "\n";
475
}
476
477
static void emitBasicReaderWriterMethodSuffix(raw_ostream &out,
478
PropertyType type,
479
bool isForRead) {
480
if (!type.isGenericSpecialization()) {
481
out << type.getAbstractTypeName();
482
} else if (auto eltType = type.getArrayElementType()) {
483
out << "Array";
484
// We only include an explicit template argument for reads so that
485
// we don't cause spurious const mismatches.
486
if (isForRead) {
487
out << "<";
488
eltType.emitCXXValueTypeName(isForRead, out);
489
out << ">";
490
}
491
} else if (auto valueType = type.getOptionalElementType()) {
492
out << "Optional";
493
// We only include an explicit template argument for reads so that
494
// we don't cause spurious const mismatches.
495
if (isForRead) {
496
out << "<";
497
valueType.emitCXXValueTypeName(isForRead, out);
498
out << ">";
499
}
500
} else {
501
PrintFatalError(type.getLoc(), "unexpected generic property type");
502
}
503
}
504
505
/// Emit code to read the given property in a node-reader method.
506
void ASTPropsEmitter::emitReadOfProperty(StringRef readerName,
507
Property property) {
508
emitReadOfProperty(readerName, property.getName(), property.getType(),
509
property.getCondition());
510
}
511
512
void ASTPropsEmitter::emitReadOfProperty(StringRef readerName,
513
StringRef name,
514
PropertyType type,
515
StringRef condition) {
516
// Declare all the necessary buffers.
517
auto bufferTypes = type.getBufferElementTypes();
518
for (size_t i = 0, e = bufferTypes.size(); i != e; ++i) {
519
Out << " llvm::SmallVector<";
520
PropertyType(bufferTypes[i]).emitCXXValueTypeName(/*for read*/ true, Out);
521
Out << ", 8> " << name << "_buffer_" << i << ";\n";
522
}
523
524
// T prop = R.find("prop").read##ValueType(buffers...);
525
// We intentionally ignore shouldPassByReference here: we're going to
526
// get a pr-value back from read(), and we should be able to forward
527
// that in the creation rule.
528
Out << " ";
529
if (!condition.empty())
530
Out << "std::optional<";
531
type.emitCXXValueTypeName(true, Out);
532
if (!condition.empty()) Out << ">";
533
Out << " " << name;
534
535
if (condition.empty()) {
536
Out << " = ";
537
} else {
538
Out << ";\n"
539
" if (" << condition << ") {\n"
540
" " << name << ".emplace(";
541
}
542
543
Out << readerName << ".find(\"" << name << "\")."
544
<< (type.isGenericSpecialization() ? "template " : "") << "read";
545
emitBasicReaderWriterMethodSuffix(Out, type, /*for read*/ true);
546
Out << "(";
547
for (size_t i = 0, e = bufferTypes.size(); i != e; ++i) {
548
Out << (i > 0 ? ", " : "") << name << "_buffer_" << i;
549
}
550
Out << ")";
551
552
if (condition.empty()) {
553
Out << ";\n";
554
} else {
555
Out << ");\n"
556
" }\n";
557
}
558
}
559
560
/// Emit code to write the given property in a node-writer method.
561
void ASTPropsEmitter::emitWriteOfProperty(StringRef writerName,
562
Property property) {
563
emitWriteOfProperty(writerName, property.getName(), property.getType(),
564
property.getReadCode(), property.getCondition());
565
}
566
567
void ASTPropsEmitter::emitWriteOfProperty(StringRef writerName,
568
StringRef name,
569
PropertyType type,
570
StringRef readCode,
571
StringRef condition) {
572
if (!condition.empty()) {
573
Out << " if (" << condition << ") {\n";
574
}
575
576
// Focus down to the property:
577
// T prop = <READ>;
578
// W.find("prop").write##ValueType(prop);
579
Out << " ";
580
type.emitCXXValueTypeName(false, Out);
581
Out << " " << name << " = (" << readCode << ");\n"
582
" " << writerName << ".find(\"" << name << "\").write";
583
emitBasicReaderWriterMethodSuffix(Out, type, /*for read*/ false);
584
Out << "(" << name << ");\n";
585
586
if (!condition.empty()) {
587
Out << " }\n";
588
}
589
}
590
591
/// Emit an .inc file that defines the AbstractFooReader class
592
/// for the given AST class hierarchy.
593
template <class NodeClass>
594
static void emitASTReader(RecordKeeper &records, raw_ostream &out,
595
StringRef description) {
596
emitSourceFileHeader(description, out, records);
597
598
ASTPropsEmitter(records, out).emitNodeReaderClass<NodeClass>();
599
}
600
601
void clang::EmitClangTypeReader(RecordKeeper &records, raw_ostream &out) {
602
emitASTReader<TypeNode>(records, out, "A CRTP reader for Clang Type nodes");
603
}
604
605
/// Emit an .inc file that defines the AbstractFooWriter class
606
/// for the given AST class hierarchy.
607
template <class NodeClass>
608
static void emitASTWriter(RecordKeeper &records, raw_ostream &out,
609
StringRef description) {
610
emitSourceFileHeader(description, out, records);
611
612
ASTPropsEmitter(records, out).emitNodeWriterClass<NodeClass>();
613
}
614
615
void clang::EmitClangTypeWriter(RecordKeeper &records, raw_ostream &out) {
616
emitASTWriter<TypeNode>(records, out, "A CRTP writer for Clang Type nodes");
617
}
618
619
/****************************************************************************/
620
/*************************** BASIC READER/WRITERS ***************************/
621
/****************************************************************************/
622
623
void
624
ASTPropsEmitter::emitDispatcherTemplate(const ReaderWriterInfo &info) {
625
// Declare the {Read,Write}Dispatcher template.
626
StringRef dispatcherPrefix = (info.IsReader ? "Read" : "Write");
627
Out << "template <class ValueType>\n"
628
"struct " << dispatcherPrefix << "Dispatcher;\n";
629
630
// Declare a specific specialization of the dispatcher template.
631
auto declareSpecialization =
632
[&](StringRef specializationParameters,
633
const Twine &cxxTypeName,
634
StringRef methodSuffix) {
635
StringRef var = info.HelperVariable;
636
Out << "template " << specializationParameters << "\n"
637
"struct " << dispatcherPrefix << "Dispatcher<"
638
<< cxxTypeName << "> {\n";
639
Out << " template <class Basic" << info.ClassSuffix << ", class... Args>\n"
640
" static " << (info.IsReader ? cxxTypeName : "void") << " "
641
<< info.MethodPrefix
642
<< "(Basic" << info.ClassSuffix << " &" << var
643
<< ", Args &&... args) {\n"
644
" return " << var << "."
645
<< info.MethodPrefix << methodSuffix
646
<< "(std::forward<Args>(args)...);\n"
647
" }\n"
648
"};\n";
649
};
650
651
// Declare explicit specializations for each of the concrete types.
652
for (PropertyType type : AllPropertyTypes) {
653
declareSpecialization("<>",
654
type.getCXXTypeName(),
655
type.getAbstractTypeName());
656
// Also declare a specialization for the const type when appropriate.
657
if (!info.IsReader && type.isConstWhenWriting()) {
658
declareSpecialization("<>",
659
"const " + type.getCXXTypeName(),
660
type.getAbstractTypeName());
661
}
662
}
663
// Declare partial specializations for ArrayRef and Optional.
664
declareSpecialization("<class T>",
665
"llvm::ArrayRef<T>",
666
"Array");
667
declareSpecialization("<class T>", "std::optional<T>", "Optional");
668
Out << "\n";
669
}
670
671
void
672
ASTPropsEmitter::emitPackUnpackOptionalTemplate(const ReaderWriterInfo &info) {
673
StringRef classPrefix = (info.IsReader ? "Unpack" : "Pack");
674
StringRef methodName = (info.IsReader ? "unpack" : "pack");
675
676
// Declare the {Pack,Unpack}OptionalValue template.
677
Out << "template <class ValueType>\n"
678
"struct " << classPrefix << "OptionalValue;\n";
679
680
auto declareSpecialization = [&](const Twine &typeName, StringRef code) {
681
Out << "template <>\n"
682
"struct "
683
<< classPrefix << "OptionalValue<" << typeName
684
<< "> {\n"
685
" static "
686
<< (info.IsReader ? "std::optional<" : "") << typeName
687
<< (info.IsReader ? "> " : " ") << methodName << "("
688
<< (info.IsReader ? "" : "std::optional<") << typeName
689
<< (info.IsReader ? "" : ">")
690
<< " value) {\n"
691
" return "
692
<< code
693
<< ";\n"
694
" }\n"
695
"};\n";
696
};
697
698
for (PropertyType type : AllPropertyTypes) {
699
StringRef code = (info.IsReader ? type.getUnpackOptionalCode()
700
: type.getPackOptionalCode());
701
if (code.empty()) continue;
702
703
StringRef typeName = type.getCXXTypeName();
704
declareSpecialization(typeName, code);
705
if (type.isConstWhenWriting() && !info.IsReader)
706
declareSpecialization("const " + typeName, code);
707
}
708
Out << "\n";
709
}
710
711
void
712
ASTPropsEmitter::emitBasicReaderWriterTemplate(const ReaderWriterInfo &info) {
713
// Emit the Basic{Reader,Writer}Base template.
714
Out << "template <class Impl>\n"
715
"class Basic" << info.ClassSuffix << "Base {\n";
716
Out << " ASTContext &C;\n";
717
Out << "protected:\n"
718
" Basic"
719
<< info.ClassSuffix << "Base" << ("(ASTContext &ctx) : C(ctx)")
720
<< " {}\n"
721
"public:\n";
722
Out << " ASTContext &getASTContext() { return C; }\n";
723
Out << " Impl &asImpl() { return static_cast<Impl&>(*this); }\n";
724
725
auto enterReaderWriterMethod = [&](StringRef cxxTypeName,
726
StringRef abstractTypeName,
727
bool shouldPassByReference,
728
bool constWhenWriting,
729
StringRef paramName) {
730
Out << " " << (info.IsReader ? cxxTypeName : "void")
731
<< " " << info.MethodPrefix << abstractTypeName << "(";
732
if (!info.IsReader)
733
Out << (shouldPassByReference || constWhenWriting ? "const " : "")
734
<< cxxTypeName
735
<< (shouldPassByReference ? " &" : "") << " " << paramName;
736
Out << ") {\n";
737
};
738
739
// Emit {read,write}ValueType methods for all the enum and subclass types
740
// that default to using the integer/base-class implementations.
741
for (PropertyType type : AllPropertyTypes) {
742
auto enterMethod = [&](StringRef paramName) {
743
enterReaderWriterMethod(type.getCXXTypeName(),
744
type.getAbstractTypeName(),
745
type.shouldPassByReference(),
746
type.isConstWhenWriting(),
747
paramName);
748
};
749
auto exitMethod = [&] {
750
Out << " }\n";
751
};
752
753
// Handled cased types.
754
auto casedIter = CasedTypeInfos.find(type);
755
if (casedIter != CasedTypeInfos.end()) {
756
enterMethod("node");
757
emitCasedReaderWriterMethodBody(type, casedIter->second, info);
758
exitMethod();
759
760
} else if (type.isEnum()) {
761
enterMethod("value");
762
if (info.IsReader)
763
Out << " return asImpl().template readEnum<"
764
<< type.getCXXTypeName() << ">();\n";
765
else
766
Out << " asImpl().writeEnum(value);\n";
767
exitMethod();
768
769
} else if (PropertyType superclass = type.getSuperclassType()) {
770
enterMethod("value");
771
if (info.IsReader)
772
Out << " return cast_or_null<" << type.getSubclassClassName()
773
<< ">(asImpl().read"
774
<< superclass.getAbstractTypeName()
775
<< "());\n";
776
else
777
Out << " asImpl().write" << superclass.getAbstractTypeName()
778
<< "(value);\n";
779
exitMethod();
780
781
} else {
782
// The other types can't be handled as trivially.
783
}
784
}
785
Out << "};\n\n";
786
}
787
788
void ASTPropsEmitter::emitCasedReaderWriterMethodBody(PropertyType type,
789
const CasedTypeInfo &typeCases,
790
const ReaderWriterInfo &info) {
791
if (typeCases.Cases.empty()) {
792
assert(typeCases.KindRule);
793
PrintFatalError(typeCases.KindRule.getLoc(),
794
"no cases found for \"" + type.getCXXTypeName() + "\"");
795
}
796
if (!typeCases.KindRule) {
797
assert(!typeCases.Cases.empty());
798
PrintFatalError(typeCases.Cases.front().getLoc(),
799
"no kind rule for \"" + type.getCXXTypeName() + "\"");
800
}
801
802
auto var = info.HelperVariable;
803
std::string subvar = ("sub" + var).str();
804
805
// Bind `ctx` for readers.
806
if (info.IsReader)
807
Out << " auto &ctx = asImpl().getASTContext();\n";
808
809
// Start an object.
810
Out << " auto &&" << subvar << " = asImpl()."
811
<< info.MethodPrefix << "Object();\n";
812
813
// Read/write the kind property;
814
TypeKindRule kindRule = typeCases.KindRule;
815
StringRef kindProperty = kindRule.getKindPropertyName();
816
PropertyType kindType = kindRule.getKindType();
817
if (info.IsReader) {
818
emitReadOfProperty(subvar, kindProperty, kindType);
819
} else {
820
// Write the property. Note that this will implicitly read the
821
// kind into a local variable with the right name.
822
emitWriteOfProperty(subvar, kindProperty, kindType,
823
kindRule.getReadCode());
824
}
825
826
// Prepare a ReaderWriterInfo with a helper variable that will use
827
// the sub-reader/writer.
828
ReaderWriterInfo subInfo = info;
829
subInfo.HelperVariable = subvar;
830
831
// Switch on the kind.
832
Out << " switch (" << kindProperty << ") {\n";
833
for (TypeCase typeCase : typeCases.Cases) {
834
Out << " case " << type.getCXXTypeName() << "::"
835
<< typeCase.getCaseName() << ": {\n";
836
emitPropertiedReaderWriterBody(typeCase, subInfo);
837
if (!info.IsReader)
838
Out << " return;\n";
839
Out << " }\n\n";
840
}
841
Out << " }\n"
842
" llvm_unreachable(\"bad " << kindType.getCXXTypeName()
843
<< "\");\n";
844
}
845
846
void ASTPropsEmitter::emitBasicReaderWriterFile(const ReaderWriterInfo &info) {
847
emitDispatcherTemplate(info);
848
emitPackUnpackOptionalTemplate(info);
849
emitBasicReaderWriterTemplate(info);
850
}
851
852
/// Emit an .inc file that defines some helper classes for reading
853
/// basic values.
854
void clang::EmitClangBasicReader(RecordKeeper &records, raw_ostream &out) {
855
emitSourceFileHeader("Helper classes for BasicReaders", out, records);
856
857
// Use any property, we won't be using those properties.
858
auto info = ReaderWriterInfo::forReader<TypeNode>();
859
ASTPropsEmitter(records, out).emitBasicReaderWriterFile(info);
860
}
861
862
/// Emit an .inc file that defines some helper classes for writing
863
/// basic values.
864
void clang::EmitClangBasicWriter(RecordKeeper &records, raw_ostream &out) {
865
emitSourceFileHeader("Helper classes for BasicWriters", out, records);
866
867
// Use any property, we won't be using those properties.
868
auto info = ReaderWriterInfo::forWriter<TypeNode>();
869
ASTPropsEmitter(records, out).emitBasicReaderWriterFile(info);
870
}
871
872