Home | History | Annotate | Line # | Download | only in TableGen
      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