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 "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(Name: className); |
112 | } |
113 | |
114 | template <class NodeClass> |
115 | NodeClass getAs() const { |
116 | return (isSubClassOf(className: 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 | |