1//=== ASTTableGen.h - Common definitions for AST node tablegen --*- 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#ifndef CLANG_AST_TABLEGEN_H
10#define CLANG_AST_TABLEGEN_H
11
12#include "llvm/TableGen/Record.h"
13#include "llvm/ADT/STLExtras.h"
14#include <optional>
15
16// These are spellings in the tblgen files.
17
18#define HasPropertiesClassName "HasProperties"
19
20// ASTNodes and their common fields.  `Base` is actually defined
21// in subclasses, but it's still common across the hierarchies.
22#define ASTNodeClassName "ASTNode"
23#define BaseFieldName "Base"
24#define AbstractFieldName "Abstract"
25
26// Comment node hierarchy.
27#define CommentNodeClassName "CommentNode"
28
29// Decl node hierarchy.
30#define DeclNodeClassName "DeclNode"
31#define DeclContextNodeClassName "DeclContext"
32
33// Stmt node hierarchy.
34#define StmtNodeClassName "StmtNode"
35
36// Type node hierarchy.
37#define TypeNodeClassName "TypeNode"
38#define AlwaysDependentClassName "AlwaysDependent"
39#define NeverCanonicalClassName "NeverCanonical"
40#define NeverCanonicalUnlessDependentClassName "NeverCanonicalUnlessDependent"
41#define LeafTypeClassName "LeafType"
42
43// Cases of various non-ASTNode structured types like DeclarationName.
44#define TypeKindClassName "PropertyTypeKind"
45#define KindTypeFieldName "KindType"
46#define KindPropertyNameFieldName "KindPropertyName"
47#define TypeCaseClassName "PropertyTypeCase"
48
49// Properties of AST nodes.
50#define PropertyClassName "Property"
51#define ClassFieldName "Class"
52#define NameFieldName "Name"
53#define TypeFieldName "Type"
54#define ReadFieldName "Read"
55
56// Types of properties.
57#define PropertyTypeClassName "PropertyType"
58#define CXXTypeNameFieldName "CXXName"
59#define PassByReferenceFieldName "PassByReference"
60#define ConstWhenWritingFieldName "ConstWhenWriting"
61#define ConditionalCodeFieldName "Conditional"
62#define PackOptionalCodeFieldName "PackOptional"
63#define UnpackOptionalCodeFieldName "UnpackOptional"
64#define BufferElementTypesFieldName "BufferElementTypes"
65#define ArrayTypeClassName "Array"
66#define ArrayElementTypeFieldName "Element"
67#define OptionalTypeClassName "Optional"
68#define OptionalElementTypeFieldName "Element"
69#define SubclassPropertyTypeClassName "SubclassPropertyType"
70#define SubclassBaseTypeFieldName "Base"
71#define SubclassClassNameFieldName "SubclassName"
72#define EnumPropertyTypeClassName "EnumPropertyType"
73
74// Write helper rules.
75#define ReadHelperRuleClassName "ReadHelper"
76#define HelperCodeFieldName "Code"
77
78// Creation rules.
79#define CreationRuleClassName "Creator"
80#define CreateFieldName "Create"
81
82// Override rules.
83#define OverrideRuleClassName "Override"
84#define IgnoredPropertiesFieldName "IgnoredProperties"
85
86namespace clang {
87namespace tblgen {
88
89class WrappedRecord {
90  llvm::Record *Record;
91
92protected:
93  WrappedRecord(llvm::Record *record = nullptr) : Record(record) {}
94
95  llvm::Record *get() const {
96    assert(Record && "accessing null record");
97    return Record;
98  }
99
100public:
101  llvm::Record *getRecord() const { return Record; }
102
103  explicit operator bool() const { return Record != nullptr; }
104
105  llvm::ArrayRef<llvm::SMLoc> getLoc() const {
106    return get()->getLoc();
107  }
108
109  /// Does the node inherit from the given TableGen class?
110  bool isSubClassOf(llvm::StringRef className) const {
111    return get()->isSubClassOf(className);
112  }
113
114  template <class NodeClass>
115  NodeClass getAs() const {
116    return (isSubClassOf(NodeClass::getTableGenNodeClassName())
117              ? NodeClass(get()) : NodeClass());
118  }
119
120  friend bool operator<(WrappedRecord lhs, WrappedRecord rhs) {
121    assert(lhs && rhs && "sorting null nodes");
122    return lhs.get()->getName() < rhs.get()->getName();
123  }
124  friend bool operator>(WrappedRecord lhs, WrappedRecord rhs) {
125    return rhs < lhs;
126  }
127  friend bool operator<=(WrappedRecord lhs, WrappedRecord rhs) {
128    return !(rhs < lhs);
129  }
130  friend bool operator>=(WrappedRecord lhs, WrappedRecord rhs) {
131    return !(lhs < rhs);
132  }
133  friend bool operator==(WrappedRecord lhs, WrappedRecord rhs) {
134    // This should handle null nodes.
135    return lhs.getRecord() == rhs.getRecord();
136  }
137  friend bool operator!=(WrappedRecord lhs, WrappedRecord rhs) {
138    return !(lhs == rhs);
139  }
140};
141
142/// Anything in the AST that has properties.
143class HasProperties : public WrappedRecord {
144public:
145  static constexpr llvm::StringRef ClassName = HasPropertiesClassName;
146
147  HasProperties(llvm::Record *record = nullptr) : WrappedRecord(record) {}
148
149  llvm::StringRef getName() const;
150
151  static llvm::StringRef getTableGenNodeClassName() {
152    return HasPropertiesClassName;
153  }
154};
155
156/// An (optional) reference to a TableGen node representing a class
157/// in one of Clang's AST hierarchies.
158class ASTNode : public HasProperties {
159public:
160  ASTNode(llvm::Record *record = nullptr) : HasProperties(record) {}
161
162  llvm::StringRef getName() const {
163    return get()->getName();
164  }
165
166  /// Return the node for the base, if there is one.
167  ASTNode getBase() const {
168    return get()->getValueAsOptionalDef(BaseFieldName);
169  }
170
171  /// Is the corresponding class abstract?
172  bool isAbstract() const {
173    return get()->getValueAsBit(AbstractFieldName);
174  }
175
176  static llvm::StringRef getTableGenNodeClassName() {
177    return ASTNodeClassName;
178  }
179};
180
181class DeclNode : public ASTNode {
182public:
183  DeclNode(llvm::Record *record = nullptr) : ASTNode(record) {}
184
185  llvm::StringRef getId() const;
186  std::string getClassName() const;
187  DeclNode getBase() const { return DeclNode(ASTNode::getBase().getRecord()); }
188
189  static llvm::StringRef getASTHierarchyName() {
190    return "Decl";
191  }
192  static llvm::StringRef getASTIdTypeName() {
193    return "Decl::Kind";
194  }
195  static llvm::StringRef getASTIdAccessorName() {
196    return "getKind";
197  }
198  static llvm::StringRef getTableGenNodeClassName() {
199    return DeclNodeClassName;
200  }
201};
202
203class TypeNode : public ASTNode {
204public:
205  TypeNode(llvm::Record *record = nullptr) : ASTNode(record) {}
206
207  llvm::StringRef getId() const;
208  llvm::StringRef getClassName() const;
209  TypeNode getBase() const { return TypeNode(ASTNode::getBase().getRecord()); }
210
211  static llvm::StringRef getASTHierarchyName() {
212    return "Type";
213  }
214  static llvm::StringRef getASTIdTypeName() {
215    return "Type::TypeClass";
216  }
217  static llvm::StringRef getASTIdAccessorName() {
218    return "getTypeClass";
219  }
220  static llvm::StringRef getTableGenNodeClassName() {
221    return TypeNodeClassName;
222  }
223};
224
225class StmtNode : public ASTNode {
226public:
227  StmtNode(llvm::Record *record = nullptr) : ASTNode(record) {}
228
229  std::string getId() const;
230  llvm::StringRef getClassName() const;
231  StmtNode getBase() const { return StmtNode(ASTNode::getBase().getRecord()); }
232
233  static llvm::StringRef getASTHierarchyName() {
234    return "Stmt";
235  }
236  static llvm::StringRef getASTIdTypeName() {
237    return "Stmt::StmtClass";
238  }
239  static llvm::StringRef getASTIdAccessorName() {
240    return "getStmtClass";
241  }
242  static llvm::StringRef getTableGenNodeClassName() {
243    return StmtNodeClassName;
244  }
245};
246
247/// The type of a property.
248class PropertyType : public WrappedRecord {
249public:
250  PropertyType(llvm::Record *record = nullptr) : WrappedRecord(record) {}
251
252  /// Is this a generic specialization (i.e. `Array<T>` or `Optional<T>`)?
253  bool isGenericSpecialization() const {
254    return get()->isAnonymous();
255  }
256
257  /// The abstract type name of the property.  Doesn't work for generic
258  /// specializations.
259  llvm::StringRef getAbstractTypeName() const {
260    return get()->getName();
261  }
262
263  /// The C++ type name of the property.  Doesn't work for generic
264  /// specializations.
265  llvm::StringRef getCXXTypeName() const {
266    return get()->getValueAsString(CXXTypeNameFieldName);
267  }
268  void emitCXXValueTypeName(bool forRead, llvm::raw_ostream &out) const;
269
270  /// Whether the C++ type should be passed around by reference.
271  bool shouldPassByReference() const {
272    return get()->getValueAsBit(PassByReferenceFieldName);
273  }
274
275  /// Whether the C++ type should have 'const' prepended when working with
276  /// a value of the type being written.
277  bool isConstWhenWriting() const {
278    return get()->getValueAsBit(ConstWhenWritingFieldName);
279  }
280
281  /// If this is `Array<T>`, return `T`; otherwise return null.
282  PropertyType getArrayElementType() const {
283    if (isSubClassOf(ArrayTypeClassName))
284      return get()->getValueAsDef(ArrayElementTypeFieldName);
285    return nullptr;
286  }
287
288  /// If this is `Optional<T>`, return `T`; otherwise return null.
289  PropertyType getOptionalElementType() const {
290    if (isSubClassOf(OptionalTypeClassName))
291      return get()->getValueAsDef(OptionalElementTypeFieldName);
292    return nullptr;
293  }
294
295  /// If this is a subclass type, return its superclass type.
296  PropertyType getSuperclassType() const {
297    if (isSubClassOf(SubclassPropertyTypeClassName))
298      return get()->getValueAsDef(SubclassBaseTypeFieldName);
299    return nullptr;
300  }
301
302  // Given that this is a subclass type, return the C++ name of its
303  // subclass type.  This is just the bare class name, suitable for
304  // use in `cast<>`.
305  llvm::StringRef getSubclassClassName() const {
306    return get()->getValueAsString(SubclassClassNameFieldName);
307  }
308
309  /// Does this represent an enum type?
310  bool isEnum() const {
311    return isSubClassOf(EnumPropertyTypeClassName);
312  }
313
314  llvm::StringRef getPackOptionalCode() const {
315    return get()->getValueAsString(PackOptionalCodeFieldName);
316  }
317
318  llvm::StringRef getUnpackOptionalCode() const {
319    return get()->getValueAsString(UnpackOptionalCodeFieldName);
320  }
321
322  std::vector<llvm::Record*> getBufferElementTypes() const {
323    return get()->getValueAsListOfDefs(BufferElementTypesFieldName);
324  }
325
326  static llvm::StringRef getTableGenNodeClassName() {
327    return PropertyTypeClassName;
328  }
329};
330
331/// A rule for returning the kind of a type.
332class TypeKindRule : public WrappedRecord {
333public:
334  TypeKindRule(llvm::Record *record = nullptr) : WrappedRecord(record) {}
335
336  /// Return the type to which this applies.
337  PropertyType getParentType() const {
338    return get()->getValueAsDef(TypeFieldName);
339  }
340
341  /// Return the type of the kind.
342  PropertyType getKindType() const {
343    return get()->getValueAsDef(KindTypeFieldName);
344  }
345
346  /// Return the name to use for the kind property.
347  llvm::StringRef getKindPropertyName() const {
348    return get()->getValueAsString(KindPropertyNameFieldName);
349  }
350
351  /// Return the code for reading the kind value.
352  llvm::StringRef getReadCode() const {
353    return get()->getValueAsString(ReadFieldName);
354  }
355
356  static llvm::StringRef getTableGenNodeClassName() {
357    return TypeKindClassName;
358  }
359};
360
361/// An implementation case of a property type.
362class TypeCase : public HasProperties {
363public:
364  TypeCase(llvm::Record *record = nullptr) : HasProperties(record) {}
365
366  /// Return the name of this case.
367  llvm::StringRef getCaseName() const {
368    return get()->getValueAsString(NameFieldName);
369  }
370
371  /// Return the type of which this is a case.
372  PropertyType getParentType() const {
373    return get()->getValueAsDef(TypeFieldName);
374  }
375
376  static llvm::StringRef getTableGenNodeClassName() {
377    return TypeCaseClassName;
378  }
379};
380
381/// A property of an AST node.
382class Property : public WrappedRecord {
383public:
384  Property(llvm::Record *record = nullptr) : WrappedRecord(record) {}
385
386  /// Return the name of this property.
387  llvm::StringRef getName() const {
388    return get()->getValueAsString(NameFieldName);
389  }
390
391  /// Return the type of this property.
392  PropertyType getType() const {
393    return get()->getValueAsDef(TypeFieldName);
394  }
395
396  /// Return the class of which this is a property.
397  HasProperties getClass() const {
398    return get()->getValueAsDef(ClassFieldName);
399  }
400
401  /// Return the code for reading this property.
402  llvm::StringRef getReadCode() const {
403    return get()->getValueAsString(ReadFieldName);
404  }
405
406  /// Return the code for determining whether to add this property.
407  llvm::StringRef getCondition() const {
408    return get()->getValueAsString(ConditionalCodeFieldName);
409  }
410
411  static llvm::StringRef getTableGenNodeClassName() {
412    return PropertyClassName;
413  }
414};
415
416/// A rule for running some helper code for reading properties from
417/// a value (which is actually done when writing the value out).
418class ReadHelperRule : public WrappedRecord {
419public:
420  ReadHelperRule(llvm::Record *record = nullptr) : WrappedRecord(record) {}
421
422  /// Return the class for which this is a creation rule.
423  /// Should never be abstract.
424  HasProperties getClass() const {
425    return get()->getValueAsDef(ClassFieldName);
426  }
427
428  llvm::StringRef getHelperCode() const {
429    return get()->getValueAsString(HelperCodeFieldName);
430  }
431
432  static llvm::StringRef getTableGenNodeClassName() {
433    return ReadHelperRuleClassName;
434  }
435};
436
437/// A rule for how to create an AST node from its properties.
438class CreationRule : public WrappedRecord {
439public:
440  CreationRule(llvm::Record *record = nullptr) : WrappedRecord(record) {}
441
442  /// Return the class for which this is a creation rule.
443  /// Should never be abstract.
444  HasProperties getClass() const {
445    return get()->getValueAsDef(ClassFieldName);
446  }
447
448  llvm::StringRef getCreationCode() const {
449    return get()->getValueAsString(CreateFieldName);
450  }
451
452  static llvm::StringRef getTableGenNodeClassName() {
453    return CreationRuleClassName;
454  }
455};
456
457/// A rule which overrides the standard rules for serializing an AST node.
458class OverrideRule : public WrappedRecord {
459public:
460  OverrideRule(llvm::Record *record = nullptr) : WrappedRecord(record) {}
461
462  /// Return the class for which this is an override rule.
463  /// Should never be abstract.
464  HasProperties getClass() const {
465    return get()->getValueAsDef(ClassFieldName);
466  }
467
468  /// Return a set of properties that are unnecessary when serializing
469  /// this AST node.  Generally this is used for inherited properties
470  /// that are derived for this subclass.
471  std::vector<llvm::StringRef> getIgnoredProperties() const {
472    return get()->getValueAsListOfStrings(IgnoredPropertiesFieldName);
473  }
474
475  static llvm::StringRef getTableGenNodeClassName() {
476    return OverrideRuleClassName;
477  }
478};
479
480/// A visitor for an AST node hierarchy.  Note that `base` can be null for
481/// the root class.
482template <class NodeClass>
483using ASTNodeHierarchyVisitor =
484  llvm::function_ref<void(NodeClass node, NodeClass base)>;
485
486void visitASTNodeHierarchyImpl(llvm::RecordKeeper &records,
487                               llvm::StringRef nodeClassName,
488                               ASTNodeHierarchyVisitor<ASTNode> visit);
489
490template <class NodeClass>
491void visitASTNodeHierarchy(llvm::RecordKeeper &records,
492                           ASTNodeHierarchyVisitor<NodeClass> visit) {
493  visitASTNodeHierarchyImpl(records, NodeClass::getTableGenNodeClassName(),
494                            [visit](ASTNode node, ASTNode base) {
495                              visit(NodeClass(node.getRecord()),
496                                    NodeClass(base.getRecord()));
497                            });
498}
499
500} // end namespace clang::tblgen
501} // end namespace clang
502
503#endif
504