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 
85 namespace clang {
86 namespace tblgen {
87 
88 class WrappedRecord {
89   llvm::Record *Record;
90 
91 protected:
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 
99 public:
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.
142 class HasProperties : public WrappedRecord {
143 public:
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.
157 class ASTNode : public HasProperties {
158 public:
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 
180 class DeclNode : public ASTNode {
181 public:
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 
202 class TypeNode : public ASTNode {
203 public:
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 
224 class StmtNode : public ASTNode {
225 public:
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.
247 class PropertyType : public WrappedRecord {
248 public:
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.
331 class TypeKindRule : public WrappedRecord {
332 public:
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.
361 class TypeCase : public HasProperties {
362 public:
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.
381 class Property : public WrappedRecord {
382 public:
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).
417 class ReadHelperRule : public WrappedRecord {
418 public:
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.
437 class CreationRule : public WrappedRecord {
438 public:
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.
457 class OverrideRule : public WrappedRecord {
458 public:
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.
481 template <class NodeClass>
482 using ASTNodeHierarchyVisitor =
483   llvm::function_ref<void(NodeClass node, NodeClass base)>;
484 
485 void visitASTNodeHierarchyImpl(llvm::RecordKeeper &records,
486                                llvm::StringRef nodeClassName,
487                                ASTNodeHierarchyVisitor<ASTNode> visit);
488 
489 template <class NodeClass>
490 void 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