| //=== ASTTableGen.h - Common definitions for AST node tablegen --*- C++ -*-===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef CLANG_AST_TABLEGEN_H |
| #define CLANG_AST_TABLEGEN_H |
| |
| #include "llvm/TableGen/Record.h" |
| #include "llvm/ADT/STLExtras.h" |
| |
| // These are spellings in the tblgen files. |
| |
| #define HasPropertiesClassName "HasProperties" |
| |
| // ASTNodes and their common fields. `Base` is actually defined |
| // in subclasses, but it's still common across the hierarchies. |
| #define ASTNodeClassName "ASTNode" |
| #define BaseFieldName "Base" |
| #define AbstractFieldName "Abstract" |
| |
| // Comment node hierarchy. |
| #define CommentNodeClassName "CommentNode" |
| |
| // Decl node hierarchy. |
| #define DeclNodeClassName "DeclNode" |
| #define DeclContextNodeClassName "DeclContext" |
| |
| // Stmt node hierarchy. |
| #define StmtNodeClassName "StmtNode" |
| |
| // Type node hierarchy. |
| #define TypeNodeClassName "TypeNode" |
| #define AlwaysDependentClassName "AlwaysDependent" |
| #define NeverCanonicalClassName "NeverCanonical" |
| #define NeverCanonicalUnlessDependentClassName "NeverCanonicalUnlessDependent" |
| #define LeafTypeClassName "LeafType" |
| |
| // Cases of various non-ASTNode structured types like DeclarationName. |
| #define TypeKindClassName "PropertyTypeKind" |
| #define KindTypeFieldName "KindType" |
| #define KindPropertyNameFieldName "KindPropertyName" |
| #define TypeCaseClassName "PropertyTypeCase" |
| |
| // Properties of AST nodes. |
| #define PropertyClassName "Property" |
| #define ClassFieldName "Class" |
| #define NameFieldName "Name" |
| #define TypeFieldName "Type" |
| #define ReadFieldName "Read" |
| |
| // Types of properties. |
| #define PropertyTypeClassName "PropertyType" |
| #define CXXTypeNameFieldName "CXXName" |
| #define PassByReferenceFieldName "PassByReference" |
| #define ConstWhenWritingFieldName "ConstWhenWriting" |
| #define ConditionalCodeFieldName "Conditional" |
| #define PackOptionalCodeFieldName "PackOptional" |
| #define UnpackOptionalCodeFieldName "UnpackOptional" |
| #define BufferElementTypesFieldName "BufferElementTypes" |
| #define ArrayTypeClassName "Array" |
| #define ArrayElementTypeFieldName "Element" |
| #define OptionalTypeClassName "Optional" |
| #define OptionalElementTypeFieldName "Element" |
| #define SubclassPropertyTypeClassName "SubclassPropertyType" |
| #define SubclassBaseTypeFieldName "Base" |
| #define SubclassClassNameFieldName "SubclassName" |
| #define EnumPropertyTypeClassName "EnumPropertyType" |
| |
| // Write helper rules. |
| #define ReadHelperRuleClassName "ReadHelper" |
| #define HelperCodeFieldName "Code" |
| |
| // Creation rules. |
| #define CreationRuleClassName "Creator" |
| #define CreateFieldName "Create" |
| |
| // Override rules. |
| #define OverrideRuleClassName "Override" |
| #define IgnoredPropertiesFieldName "IgnoredProperties" |
| |
| namespace clang { |
| namespace tblgen { |
| |
| class WrappedRecord { |
| llvm::Record *Record; |
| |
| protected: |
| WrappedRecord(llvm::Record *record = nullptr) : Record(record) {} |
| |
| llvm::Record *get() const { |
| assert(Record && "accessing null record"); |
| return Record; |
| } |
| |
| public: |
| llvm::Record *getRecord() const { return Record; } |
| |
| explicit operator bool() const { return Record != nullptr; } |
| |
| llvm::ArrayRef<llvm::SMLoc> getLoc() const { |
| return get()->getLoc(); |
| } |
| |
| /// Does the node inherit from the given TableGen class? |
| bool isSubClassOf(llvm::StringRef className) const { |
| return get()->isSubClassOf(className); |
| } |
| |
| template <class NodeClass> |
| NodeClass getAs() const { |
| return (isSubClassOf(NodeClass::getTableGenNodeClassName()) |
| ? NodeClass(get()) : NodeClass()); |
| } |
| |
| friend bool operator<(WrappedRecord lhs, WrappedRecord rhs) { |
| assert(lhs && rhs && "sorting null nodes"); |
| return lhs.get()->getName() < rhs.get()->getName(); |
| } |
| friend bool operator>(WrappedRecord lhs, WrappedRecord rhs) { |
| return rhs < lhs; |
| } |
| friend bool operator<=(WrappedRecord lhs, WrappedRecord rhs) { |
| return !(rhs < lhs); |
| } |
| friend bool operator>=(WrappedRecord lhs, WrappedRecord rhs) { |
| return !(lhs < rhs); |
| } |
| friend bool operator==(WrappedRecord lhs, WrappedRecord rhs) { |
| // This should handle null nodes. |
| return lhs.getRecord() == rhs.getRecord(); |
| } |
| friend bool operator!=(WrappedRecord lhs, WrappedRecord rhs) { |
| return !(lhs == rhs); |
| } |
| }; |
| |
| /// Anything in the AST that has properties. |
| class HasProperties : public WrappedRecord { |
| public: |
| static constexpr llvm::StringRef ClassName = HasPropertiesClassName; |
| |
| HasProperties(llvm::Record *record = nullptr) : WrappedRecord(record) {} |
| |
| llvm::StringRef getName() const; |
| |
| static llvm::StringRef getTableGenNodeClassName() { |
| return HasPropertiesClassName; |
| } |
| }; |
| |
| /// An (optional) reference to a TableGen node representing a class |
| /// in one of Clang's AST hierarchies. |
| class ASTNode : public HasProperties { |
| public: |
| ASTNode(llvm::Record *record = nullptr) : HasProperties(record) {} |
| |
| llvm::StringRef getName() const { |
| return get()->getName(); |
| } |
| |
| /// Return the node for the base, if there is one. |
| ASTNode getBase() const { |
| return get()->getValueAsOptionalDef(BaseFieldName); |
| } |
| |
| /// Is the corresponding class abstract? |
| bool isAbstract() const { |
| return get()->getValueAsBit(AbstractFieldName); |
| } |
| |
| static llvm::StringRef getTableGenNodeClassName() { |
| return ASTNodeClassName; |
| } |
| }; |
| |
| class DeclNode : public ASTNode { |
| public: |
| DeclNode(llvm::Record *record = nullptr) : ASTNode(record) {} |
| |
| llvm::StringRef getId() const; |
| std::string getClassName() const; |
| DeclNode getBase() const { return DeclNode(ASTNode::getBase().getRecord()); } |
| |
| static llvm::StringRef getASTHierarchyName() { |
| return "Decl"; |
| } |
| static llvm::StringRef getASTIdTypeName() { |
| return "Decl::Kind"; |
| } |
| static llvm::StringRef getASTIdAccessorName() { |
| return "getKind"; |
| } |
| static llvm::StringRef getTableGenNodeClassName() { |
| return DeclNodeClassName; |
| } |
| }; |
| |
| class TypeNode : public ASTNode { |
| public: |
| TypeNode(llvm::Record *record = nullptr) : ASTNode(record) {} |
| |
| llvm::StringRef getId() const; |
| llvm::StringRef getClassName() const; |
| TypeNode getBase() const { return TypeNode(ASTNode::getBase().getRecord()); } |
| |
| static llvm::StringRef getASTHierarchyName() { |
| return "Type"; |
| } |
| static llvm::StringRef getASTIdTypeName() { |
| return "Type::TypeClass"; |
| } |
| static llvm::StringRef getASTIdAccessorName() { |
| return "getTypeClass"; |
| } |
| static llvm::StringRef getTableGenNodeClassName() { |
| return TypeNodeClassName; |
| } |
| }; |
| |
| class StmtNode : public ASTNode { |
| public: |
| StmtNode(llvm::Record *record = nullptr) : ASTNode(record) {} |
| |
| std::string getId() const; |
| llvm::StringRef getClassName() const; |
| StmtNode getBase() const { return StmtNode(ASTNode::getBase().getRecord()); } |
| |
| static llvm::StringRef getASTHierarchyName() { |
| return "Stmt"; |
| } |
| static llvm::StringRef getASTIdTypeName() { |
| return "Stmt::StmtClass"; |
| } |
| static llvm::StringRef getASTIdAccessorName() { |
| return "getStmtClass"; |
| } |
| static llvm::StringRef getTableGenNodeClassName() { |
| return StmtNodeClassName; |
| } |
| }; |
| |
| /// The type of a property. |
| class PropertyType : public WrappedRecord { |
| public: |
| PropertyType(llvm::Record *record = nullptr) : WrappedRecord(record) {} |
| |
| /// Is this a generic specialization (i.e. `Array<T>` or `Optional<T>`)? |
| bool isGenericSpecialization() const { |
| return get()->isAnonymous(); |
| } |
| |
| /// The abstract type name of the property. Doesn't work for generic |
| /// specializations. |
| llvm::StringRef getAbstractTypeName() const { |
| return get()->getName(); |
| } |
| |
| /// The C++ type name of the property. Doesn't work for generic |
| /// specializations. |
| llvm::StringRef getCXXTypeName() const { |
| return get()->getValueAsString(CXXTypeNameFieldName); |
| } |
| void emitCXXValueTypeName(bool forRead, llvm::raw_ostream &out) const; |
| |
| /// Whether the C++ type should be passed around by reference. |
| bool shouldPassByReference() const { |
| return get()->getValueAsBit(PassByReferenceFieldName); |
| } |
| |
| /// Whether the C++ type should have 'const' prepended when working with |
| /// a value of the type being written. |
| bool isConstWhenWriting() const { |
| return get()->getValueAsBit(ConstWhenWritingFieldName); |
| } |
| |
| /// If this is `Array<T>`, return `T`; otherwise return null. |
| PropertyType getArrayElementType() const { |
| if (isSubClassOf(ArrayTypeClassName)) |
| return get()->getValueAsDef(ArrayElementTypeFieldName); |
| return nullptr; |
| } |
| |
| /// If this is `Optional<T>`, return `T`; otherwise return null. |
| PropertyType getOptionalElementType() const { |
| if (isSubClassOf(OptionalTypeClassName)) |
| return get()->getValueAsDef(OptionalElementTypeFieldName); |
| return nullptr; |
| } |
| |
| /// If this is a subclass type, return its superclass type. |
| PropertyType getSuperclassType() const { |
| if (isSubClassOf(SubclassPropertyTypeClassName)) |
| return get()->getValueAsDef(SubclassBaseTypeFieldName); |
| return nullptr; |
| } |
| |
| // Given that this is a subclass type, return the C++ name of its |
| // subclass type. This is just the bare class name, suitable for |
| // use in `cast<>`. |
| llvm::StringRef getSubclassClassName() const { |
| return get()->getValueAsString(SubclassClassNameFieldName); |
| } |
| |
| /// Does this represent an enum type? |
| bool isEnum() const { |
| return isSubClassOf(EnumPropertyTypeClassName); |
| } |
| |
| llvm::StringRef getPackOptionalCode() const { |
| return get()->getValueAsString(PackOptionalCodeFieldName); |
| } |
| |
| llvm::StringRef getUnpackOptionalCode() const { |
| return get()->getValueAsString(UnpackOptionalCodeFieldName); |
| } |
| |
| std::vector<llvm::Record*> getBufferElementTypes() const { |
| return get()->getValueAsListOfDefs(BufferElementTypesFieldName); |
| } |
| |
| static llvm::StringRef getTableGenNodeClassName() { |
| return PropertyTypeClassName; |
| } |
| }; |
| |
| /// A rule for returning the kind of a type. |
| class TypeKindRule : public WrappedRecord { |
| public: |
| TypeKindRule(llvm::Record *record = nullptr) : WrappedRecord(record) {} |
| |
| /// Return the type to which this applies. |
| PropertyType getParentType() const { |
| return get()->getValueAsDef(TypeFieldName); |
| } |
| |
| /// Return the type of the kind. |
| PropertyType getKindType() const { |
| return get()->getValueAsDef(KindTypeFieldName); |
| } |
| |
| /// Return the name to use for the kind property. |
| llvm::StringRef getKindPropertyName() const { |
| return get()->getValueAsString(KindPropertyNameFieldName); |
| } |
| |
| /// Return the code for reading the kind value. |
| llvm::StringRef getReadCode() const { |
| return get()->getValueAsString(ReadFieldName); |
| } |
| |
| static llvm::StringRef getTableGenNodeClassName() { |
| return TypeKindClassName; |
| } |
| }; |
| |
| /// An implementation case of a property type. |
| class TypeCase : public HasProperties { |
| public: |
| TypeCase(llvm::Record *record = nullptr) : HasProperties(record) {} |
| |
| /// Return the name of this case. |
| llvm::StringRef getCaseName() const { |
| return get()->getValueAsString(NameFieldName); |
| } |
| |
| /// Return the type of which this is a case. |
| PropertyType getParentType() const { |
| return get()->getValueAsDef(TypeFieldName); |
| } |
| |
| static llvm::StringRef getTableGenNodeClassName() { |
| return TypeCaseClassName; |
| } |
| }; |
| |
| /// A property of an AST node. |
| class Property : public WrappedRecord { |
| public: |
| Property(llvm::Record *record = nullptr) : WrappedRecord(record) {} |
| |
| /// Return the name of this property. |
| llvm::StringRef getName() const { |
| return get()->getValueAsString(NameFieldName); |
| } |
| |
| /// Return the type of this property. |
| PropertyType getType() const { |
| return get()->getValueAsDef(TypeFieldName); |
| } |
| |
| /// Return the class of which this is a property. |
| HasProperties getClass() const { |
| return get()->getValueAsDef(ClassFieldName); |
| } |
| |
| /// Return the code for reading this property. |
| llvm::StringRef getReadCode() const { |
| return get()->getValueAsString(ReadFieldName); |
| } |
| |
| /// Return the code for determining whether to add this property. |
| llvm::StringRef getCondition() const { |
| return get()->getValueAsString(ConditionalCodeFieldName); |
| } |
| |
| static llvm::StringRef getTableGenNodeClassName() { |
| return PropertyClassName; |
| } |
| }; |
| |
| /// A rule for running some helper code for reading properties from |
| /// a value (which is actually done when writing the value out). |
| class ReadHelperRule : public WrappedRecord { |
| public: |
| ReadHelperRule(llvm::Record *record = nullptr) : WrappedRecord(record) {} |
| |
| /// Return the class for which this is a creation rule. |
| /// Should never be abstract. |
| HasProperties getClass() const { |
| return get()->getValueAsDef(ClassFieldName); |
| } |
| |
| llvm::StringRef getHelperCode() const { |
| return get()->getValueAsString(HelperCodeFieldName); |
| } |
| |
| static llvm::StringRef getTableGenNodeClassName() { |
| return ReadHelperRuleClassName; |
| } |
| }; |
| |
| /// A rule for how to create an AST node from its properties. |
| class CreationRule : public WrappedRecord { |
| public: |
| CreationRule(llvm::Record *record = nullptr) : WrappedRecord(record) {} |
| |
| /// Return the class for which this is a creation rule. |
| /// Should never be abstract. |
| HasProperties getClass() const { |
| return get()->getValueAsDef(ClassFieldName); |
| } |
| |
| llvm::StringRef getCreationCode() const { |
| return get()->getValueAsString(CreateFieldName); |
| } |
| |
| static llvm::StringRef getTableGenNodeClassName() { |
| return CreationRuleClassName; |
| } |
| }; |
| |
| /// A rule which overrides the standard rules for serializing an AST node. |
| class OverrideRule : public WrappedRecord { |
| public: |
| OverrideRule(llvm::Record *record = nullptr) : WrappedRecord(record) {} |
| |
| /// Return the class for which this is an override rule. |
| /// Should never be abstract. |
| HasProperties getClass() const { |
| return get()->getValueAsDef(ClassFieldName); |
| } |
| |
| /// Return a set of properties that are unnecessary when serializing |
| /// this AST node. Generally this is used for inherited properties |
| /// that are derived for this subclass. |
| std::vector<llvm::StringRef> getIgnoredProperties() const { |
| return get()->getValueAsListOfStrings(IgnoredPropertiesFieldName); |
| } |
| |
| static llvm::StringRef getTableGenNodeClassName() { |
| return OverrideRuleClassName; |
| } |
| }; |
| |
| /// A visitor for an AST node hierarchy. Note that `base` can be null for |
| /// the root class. |
| template <class NodeClass> |
| using ASTNodeHierarchyVisitor = |
| llvm::function_ref<void(NodeClass node, NodeClass base)>; |
| |
| void visitASTNodeHierarchyImpl(llvm::RecordKeeper &records, |
| llvm::StringRef nodeClassName, |
| ASTNodeHierarchyVisitor<ASTNode> visit); |
| |
| template <class NodeClass> |
| void visitASTNodeHierarchy(llvm::RecordKeeper &records, |
| ASTNodeHierarchyVisitor<NodeClass> visit) { |
| visitASTNodeHierarchyImpl(records, NodeClass::getTableGenNodeClassName(), |
| [visit](ASTNode node, ASTNode base) { |
| visit(NodeClass(node.getRecord()), |
| NodeClass(base.getRecord())); |
| }); |
| } |
| |
| } // end namespace clang::tblgen |
| } // end namespace clang |
| |
| #endif |