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