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 
86 namespace clang {
87 namespace tblgen {
88 
89 class WrappedRecord {
90   llvm::Record *Record;
91 
92 protected:
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 
100 public:
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.
143 class HasProperties : public WrappedRecord {
144 public:
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.
158 class ASTNode : public HasProperties {
159 public:
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 
181 class DeclNode : public ASTNode {
182 public:
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 
203 class TypeNode : public ASTNode {
204 public:
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 
225 class StmtNode : public ASTNode {
226 public:
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.
248 class PropertyType : public WrappedRecord {
249 public:
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.
332 class TypeKindRule : public WrappedRecord {
333 public:
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.
362 class TypeCase : public HasProperties {
363 public:
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.
382 class Property : public WrappedRecord {
383 public:
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).
418 class ReadHelperRule : public WrappedRecord {
419 public:
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.
438 class CreationRule : public WrappedRecord {
439 public:
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.
458 class OverrideRule : public WrappedRecord {
459 public:
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.
482 template <class NodeClass>
483 using ASTNodeHierarchyVisitor =
484   llvm::function_ref<void(NodeClass node, NodeClass base)>;
485 
486 void visitASTNodeHierarchyImpl(llvm::RecordKeeper &records,
487                                llvm::StringRef nodeClassName,
488                                ASTNodeHierarchyVisitor<ASTNode> visit);
489 
490 template <class NodeClass>
491 void 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